Setup

library(seqinr)
library(ape)  
library(pegas)
library(hierfstat)
library(mmod)
library(adegenet)
library(plyr)
library(strataG)
library(iNEXT)
library(gdm)
library(gdistance)
library(ecodist)
library(dplyr)
library(reshape2)
library(WriteXLS)
library(ggplot2)
library(knitr)
library(vegan)
source("config.R")
source("DIPnet_Stats_Functions.R")
rescale<-function(x){
  normalized<-(x-min(x))/(max(x)-min(x))
  return(normalized)
}
######################################################################
# 1. Import the IPDB and Fst tables
ipdb<-read.table(ipdb_path,sep="\t",header=T,stringsAsFactors = F,quote="", na.strings=c("NA"," ","")) 
#read in geographical regionalizations from Treml
spatial<-read.table(spatial_path, header=T, sep="\t",stringsAsFactors = F, na.strings=c("NA"," ",""), quote="")
#read in geographical regionalizations from Beger
spatial2<-read.table(spatial2_path, header=T,sep="\t", stringsAsFactors = F, na.strings=c("NA"," ",""), quote="")
#read in ABGD groups
abgd<-read.table(abgd_path, header=T, sep="\t", stringsAsFactors = F)
#join spatial
ipdb<-join(ipdb,spatial, by = "IPDB_ID",type = "left")
ipdb<-join(ipdb,spatial2[,c(2,18:24)], by = "IPDB_ID", type = "left")
#join ABGD
ipdb<-join(ipdb,abgd[,c(1,3)], by = "IPDB_ID",type = "left")
# drop hybrids and divergent individuals
ipdb<-ipdb[ipdb$IPDB_ID %in% drops == FALSE, ] 
## remove anything not included in the ecoregions scheme (some dolphins, some COTS from Kingman and Madagascar(?), some A. nigros from Kiribati, som C. auriga from Fakareva, hammerheads from Western Australia, and West Africa, and some dolphins from the middle of the eastern tropical pacific
ipdb_ecoregions<-ipdb[-which(is.na(ipdb$ECOREGION)),]
## remove anything that doesn't occur in the 3 Indo-Pacific realms
ipdb_ip<-ipdb_ecoregions[which(ipdb_ecoregions$REALM %in% c("Central Indo-Pacific","Western Indo-Pacific","Eastern Indo-Pacific")),]
amova_ts_path<-"/Users/eric/google_drive/DIPnet_Gait_Lig_Bird/DIPnet_WG4_first_papers/statistics/By_Species/Hierarchical_structure"
amova_abgd_path<-"/Users/eric/google_drive/DIPnet_Gait_Lig_Bird/DIPnet_WG4_first_papers/statistics/By_ESU/Hierarchical_structure"
# Read in Veron barriers
barriers<-read.csv("VeronBarriers.csv",header=F,stringsAsFactors = F)

Introduction

This is an R Markdown Notebook. I am trying it out as a way to reproducibly document my work on the DIPnet Population Structure Paper.

The overall workflow for this analysis is as follows:

Run AMOVA loops

Given the special considerations, we need to run 4 different flavors of AMOVA: 1. WCTheta and TradSpec 2. WCTheta and ABGD 3. PhiST and TradSpec 4. PhiST and ABGD

Thus, we need to loop through all of the regionalizations above, running all 4 flavors of AMOVA.

## Loop through hypotheses, calculating AMOVA
hypotheses<-c("ECOREGION", "PROVINCE","REALM","Bowen","Keith","Kulbicki_r","Kulbicki_b", "VeronDivis")
amova_list<-list()

for(h in hypotheses){
  hierstats<-hierarchical.structure.mtDNA.db(ipdb = ipdb_ip,level1 = "sample",level2=h,model="none",ABGD=F,nperm=1)
  amova_list[[h]]<-hierstats
}
  

## Summarize AMOVA results
amovastats<-summarize_AMOVA(amova_list,hypotheses,specieslist=unique(ipdb$Genus_species_locus))

WriteXLS(amovastats,ExcelFileName=file.path(amova_ts_path,"FST_TradSpec_raw_amova_output.Rdata.xlsx"))
save(amova_list,file=file.path(amova_ts_path,"FST_TradSpec_raw_amova_output.Rdata"))
save(amovastats,file=file.path(amova_ts_path,"FST_TradSpec_table_amova_output.Rdata"))

This takes a long time, so we are not running this code in the document, but loading in the results as we go through each consideration

Visualize AMOVA results

FST and Traditional Species Boundaries

Measure Support

load(file=file.path(amova_ts_path,"FST_TradSpec_table_amova_output.Rdata"))
# Measure support for each hypothesis
#Get the values for each hypothesis for a given criterion - here I use BIC - and rank them for #each species, then choose the "best" hypothesis for each species based on the criterion.
criterion<-"BIC"
# find the maximum number of species from any of the 8 hypotheses
maxlength<-max(sapply(amovastats,function(x) length(x[[1]]))) 
# create an empty data frame with row names from the hypothesis with the most values
crit_df<-data.frame(setNames(replicate(maxlength,numeric(0), simplify = F),nm=row.names(amovastats[["PROVINCE"]]))) 
#Loop through the hypotheses, pulling out the values for criterion,transpose it, and then merge these values into the dataframe from the previous hypothesis 
for(h in names(amovastats)){
  crit_df<-merge(crit_df,t(amovastats[[h]][criterion]),all=T,sort=F)
}
#get the hypothesis names in there
row.names(crit_df)<-names(amovastats)
#rank the hypotheses for each species
crit_rank<-as.data.frame(sapply(crit_df,rank,na.last="keep",ties.method="average"))
row.names(crit_rank)<-names(amovastats)
## remove gsls with more than 3 missing models
crit_rank<-crit_rank[, colSums(is.na(crit_rank)) < nrow(crit_rank)-5]  
## choose the best hypothesis or set of hypotheses for each species  
best_hypothesis<-sapply(crit_rank,function(x){row.names(crit_rank)[which(x==min(x,na.rm=T)) ]})
## Make a bar graph of best support for each hypothesis among species
barplot<-ggplot(data=as.data.frame(unlist(best_hypothesis)), aes(x=unlist(best_hypothesis) )) + geom_bar(aes(y = (..count..)/sum(..count..))) + labs(x="Hypothesis",y="Proportion of Species", title="Proportional Support for Biogeographic Hypotheses based on BIC")
barplot

Calculate relative probability from Johnson and Omland 2004 and visualize with a heatmap

# lookup the minimum BIC value for each species (which.min works better here, because it returns only the first instance of the minimum value)
minBIC<-sapply(crit_df,function(x){x[which.min(x)]}) 
#J&O box 4 eqn 1. scale() seems to be the way to go here, using the minBIC as the centering vector
crit_df_deltaI<-scale(crit_df, center=minBIC, scale=F) 
#J&O box 4 eqn 4. numerator, plus make it a data frame
crit_df_deltaI_b<-as.data.frame(exp(-0.5*crit_df_deltaI)) 
#J&O box 4 eqn 4. denominator
crit_df_deltaI_sums<-sapply(crit_df_deltaI_b,sum,na.rm=T) 
# this time use the scale argument of scale to divide each column by the corresponding sum
crit_df_relative_prob<-scale(crit_df_deltaI_b,center=F,scale=crit_df_deltaI_sums) 
## Make a heatmap of relative probability of each hypothesis
#melt for ggplot2
relprob<-melt(crit_df_relative_prob)
colnames(relprob)<-c("Hypothesis","Species","Relative_Probability")
#baseplot
rp<-ggplot(relprob,aes(y=Species,x=Hypothesis,fill=Relative_Probability))
#add geom_tile, turn the x-axis elements by 90 degrees, reverse the names on the y-axis, and use a diverging color scheme to highlight hypotheses with >50% rel prob.
rp<-rp+geom_tile()+
  theme(axis.text.x = element_text(angle = 90, hjust = 1))+
  ylim(rev(levels(relprob$Species)))+
  scale_fill_gradient2(low = "blue", mid = "white",
                       high = "red", midpoint = 0.5, space = "rgb",
                       na.value = "grey50", guide = "colourbar")
Non Lab interpolation is deprecated
rp

PHIST and Traditional Species Boundaries

Code is suppressed for the other 3 examples

Measure Support

Calculate relative probability from Johnson and Omland 2004 and visualize with a heatmap

Non Lab interpolation is deprecated

FST and ABGD Boundaries

Measure Support

Calculate relative probability from Johnson and Omland 2004 and visualize with a heatmap

Non Lab interpolation is deprecated

PHIST and ABGD Boundaries

Measure Support

Calculate relative probability from Johnson and Omland 2004 and visualize with a heatmap

Non Lab interpolation is deprecated

Calculate Pairwise Differentiation Stats

By sample

diffstats<-pairwise.structure.mtDNA.db(ipdb=ipdb, gdist = "WC Theta", minseqs = 5, minsamps = 3, mintotalseqs = 0, nrep = 0, num.cores = 2, ABGD = T, regionalization = "sample")


save(diffstats, file="/Users/eric/google_drive/DIPnet_Gait_Lig_Bird/DIPnet_WG4_first_papers/statistics/By_ESU/Pairwise_statistics/DIPnet_structure_sample_WCTheta_ABGD.Rdata")

diffstats<-pairwise.structure.mtDNA.db(ipdb=ipdb, gdist = "Jost D", minseqs = 5, minsamps = 3, mintotalseqs = 0, nrep = 0, num.cores = 2, ABGD = T, regionalization = "sample")


save(diffstats, file="/Users/eric/google_drive/DIPnet_Gait_Lig_Bird/DIPnet_WG4_first_papers/statistics/By_ESU/Pairwise_statistics/DIPnet_structure_sample_JostD_ABGD.Rdata")

Generalized Dissimilarity Modeling

Traditional Species Boundaries


  load("/Users/eric/google_drive/DIPnet_Gait_Lig_Bird/DIPnet_WG4_first_papers/statistics/By_Species/Pairwise_statistics/sample/DIPnet_structure_sample_WCTHETA.Rdata")

esu_loci <- unique(ipdb$Genus_species_locus)

gdm.full<-list()

solution<-list()
nosolution<-list()
nosolution.full<-list()

stats.full<-data.frame(Species_Locus=character(0),WithRegionsDeviance=numeric(0),WithRegionsExplainedDeviance=numeric(0),NoRegionsDeviance=numeric(0),NoRegionsExplainedDeviance=numeric(0),DeltaDeviance=numeric(0),Pvalue_regions=numeric(0),Pvalue_dist=numeric(0),stringsAsFactors = F)

stats<-data.frame(Species_Locus=character(0),Barrier=character(0),WithBarrierDeviance=numeric(0),WithBarrierExplainedDeviance=numeric(0),ImportanceDistanceWithBarrier=numeric(0),ImportanceBarrierWithBarrier=numeric(0),NoBarrierDeviance=numeric(0),NoBarrierExplainedDeviance=numeric(0),ImportanceDistanceWithoutBarrier=numeric(0),DeltaDeviance=numeric(0),Pvalue_barrier=numeric(0),Pvalue_dist=numeric(0),MRDM.rsquared=numeric(0),MRDM.rsquared.pvalue=numeric(0),MRDM.dist.pvalue=numeric(0), MRDM.barrier.pvalue=numeric(0),stringsAsFactors = F)

nostats<-NULL

barriertests<-data.frame(Species=character(0),Region1=character(0),NumPops1=numeric(0),Region2=character(0),Numpops2=numeric(0), Test=logical(0), Solution=logical(0),stringsAsFactors = F)

k<-0

for(gsl in esu_loci){ #gsl<-"Linckia_laevigata_CO1" "Tridacna_crocea_CO1" "Lutjanus_kasmira_CYB" "Acanthaster_planci_CO1"
  
  cat("\n","\n","\n","Now starting", gsl, "\n")
  
  if(any(is.na(diffstats[[gsl]]))){cat("NAs in FST table, No gdm calculated"); next}
  
  if(diffstats[[gsl]]=="Fewer than 3 sampled populations after filtering. No stats calculated"){nostats<-c(nostats,gsl);next}
  
  #pull out the data for this genus-species-locus (gsl)
  sp<-ipdb[which(ipdb$Genus_species_locus==gsl),]
  #clean weird backslashes from names
  sp$locality<-gsub("\"","",sp$locality)
  
  sp$sample<-paste(sp$locality,round(sp$decimalLatitude, digits=0),round(sp$decimalLongitude, digits=0),sep="_")  #sets up a variable that matches the name in Fst table
  sp<-sp[order(sp$sample),]
  # Not all localities are included in Veron's regionalization (e.g. Guam), so get their names and then zap NAs
  nonVeronpops<-unique(sp$sample[is.na(sp$VeronDivis)])
  sp<-sp[!is.na(sp$VeronDivis),]
  
  #subsample Fst 
  gslFST<-diffstats[[gsl]]
  #make a matrix out of gslFST
  gslFSTm<-as.matrix(gslFST)
  
  gslFSTm[which(gslFSTm > 1)] <- 1 #some values that look like 1.0000 are registering as greater than 1
  gslFSTm[which(gslFSTm < 0)] <- 0.0001 #get rid of artifactual negative values
  #gslFSTm<-rescale(gslFSTm)
  #gslFSTm<-gslFSTm/(1-gslFSTm)
  
  #zap weird slashes in the names
  rownames(gslFSTm)<-gsub("\"","",rownames(gslFSTm))
  colnames(gslFSTm)<-rownames(gslFSTm)
  
  #zap the same na populations from the list of non existent pops from VeronDivis
  if(any(rownames(gslFSTm) %in% nonVeronpops)){
    gslFSTm<-gslFSTm[-(which(rownames(gslFSTm) %in% nonVeronpops)),-(which(colnames(gslFSTm) %in% nonVeronpops))]
  }
  
  if(length(rownames(gslFSTm))<5){nostats<-c(nostats,gsl);cat("Fewer than 5 sampled populations");next}
  
  #and filter sp based on the localities that have Fst values
  sp<-sp[sp$sample %in% rownames(gslFSTm),]
  
  #and vice versa
  
  gslFSTm<- gslFSTm[which(rownames(gslFSTm) %in% unique(sp$sample)),which(rownames(gslFSTm) %in% unique(sp$sample))]
  


  #create a locations data frame that has all the localities plus lats and longs and their Veron region.
  locs<-as.data.frame(unique(sp$sample))
  names(locs)<-"sample"
  #locs$Long<-sp$decimalLongitude[which(locs %in% sp$sample)]
  #can't do a unique on sample, lats and longs because some samples have non-unique lats and longs! So I do a join and take the first match.
  locs<-join(locs,sp[c("sample","decimalLongitude","decimalLatitude"
                       ,"VeronDivis")], by="sample", match="first")
  
  #sort gslFSTm
  gslFSTm<-gslFSTm[order(rownames(gslFSTm)),order(colnames(gslFSTm))]
  # convert to data frame with popsample names as first column
  gslFSTm<-cbind(sample=locs$sample,as.data.frame(gslFSTm))
  
  ######################################################################
  # 3. Calculate Great Circle Distance
  gcdist_km <- pointDistance(locs[,2:3],lonlat=T)/1000
  #symmetricize the matrix
  gcdist_km[upper.tri(gcdist_km)]<-t(gcdist_km)[upper.tri(gcdist_km)]
  
  #cbind on the sample names
  gcdist_km <- cbind(sample=locs$sample,as.data.frame(gcdist_km))
  
  ####################################################################
  #4. Full Model
  
  cat("Running Full Model")
  
  
  regions<-cbind(locs[,c(1,2,3)],VeronDivis=rep_len(1,length(locs[,1])))
  if(length(unique(locs$VeronDivis)) > 1){
    regions<-cbind(locs[,c(1,2,3)],with(locs, data.frame(model.matrix(~VeronDivis+0))))
  }
  
  gslFSTmll<-cbind(locs[,c(2,3)],gslFSTm)
  
  gdm.format.full<-formatsitepair(bioData=gslFSTm, bioFormat=3, predData=regions,XColumn = "decimalLongitude", YColumn = "decimalLatitude", siteColumn="sample", distPreds=list(gcdist_km))
  
     #zap population pairs with 0 geographical distance between them. Troubling.
    zaps<-which(gdm.format.full$s2.matrix_1==0)
    
    if(length(zaps)>0) {
    gdm.format.full<-gdm.format.full[-zaps,]
    }
  
  # run the full model, and the model with only distance
  fullgdm<-gdm(gdm.format.full)
  distgdm<-gdm(gdm.format.full[,c(1:6,grep("matrix_1",names(gdm.format.full)))])
  
  if(is.null(fullgdm) | is.null(distgdm)){
        cat("No solution obtained on Full Model")
        nosolution.full[[gsl]]<-gdm.format.full
        next}
  
  # pull out stats
   #difference in deviance
    deltadev.regions<-distgdm$gdmdeviance-fullgdm$gdmdeviance
    
    #percent of null deviance explained by the model with just distance
    explaineddev.dist<-distgdm$explained
    
    gdm.regions.deviance<-fullgdm$gdmdeviance
    gdm.regions.explained<-fullgdm$explained

    gdm.no.regions.deviance<-distgdm$gdmdeviance
    gdm.no.regions.explained<-distgdm$explained
  
  ##############################################################################
    # 4A. Perform Monte-Carlo permutations to develop a null distribution 
    #    of deviance values and determine significance (pvalue)
    gdm.format.rand.full<-gdm.format.full
    rand.deltas.full<-vector() 
    rand.explained.full<-vector()
  
    while(length(rand.deltas.full) < 1000) {
      gdm.format.rand.full$distance<-sample(gdm.format.rand.full$distance,size=length(gdm.format.rand.full$distance))
      gdm.barrier.rand.full<-gdm(gdm.format.rand.full)
      gdm.no.barrier.rand.full<-gdm(gdm.format.rand.full[,c(1:6,grep("matrix_1",
                                                          names(gdm.format.rand.full)))])
    
        # if no solution obtained, go to next gsl
      if(is.null(gdm.barrier.rand.full) | is.null(gdm.no.barrier.rand.full)){next}
      
      deltadev.rand.full<-gdm.no.barrier.rand.full$gdmdeviance-gdm.barrier.rand.full$gdmdeviance
      explained.rand.full<-gdm.no.barrier.rand.full$explained
      
      rand.deltas.full<-c(rand.deltas.full,deltadev.rand.full)
      rand.explained.full<-c(rand.explained.full,explained.rand.full)
    }
    pvalue_regions.full<-length(which(abs(deltadev.regions) < abs(rand.deltas.full)))/length(rand.deltas.full)
    pvalue_dist.full<-length(which(abs(explaineddev.dist) < abs(rand.explained.full)))/length(rand.explained.full)
    
    stats.1<-c(gsl,gdm.regions.deviance,gdm.regions.explained,gdm.no.regions.deviance,gdm.no.regions.explained,deltadev.regions,pvalue_regions.full,pvalue_dist.full)
    
    stats.full[nrow(stats.full)+1,]<-stats.1
    
    gdm.full[[gsl]]<-fullgdm
    
    
}
  ####################################################################### Calculate Overwater Distances#
  #Save for later##
  #######################################################################
  # 5. Create a subset of the distance matrices including only the localities from
  #    two neighboring Veron regions.
  
  #make a table to keep track of all these tests for each species
  
  for(j in 1:16){
    k<-k+1
    barrier<-c(barriers[j,1],barriers[j,2])
    subset_locs<-which(locs$VeronDivis==barrier[1] | locs$VeronDivis==barrier[2])
    locs2<-locs[subset_locs,]
    
    
    Numpops1<-length(locs2$sample[which(locs$VeronDivis==barrier[1])])
    Numpops2<-length(locs2$sample[which(locs$VeronDivis==barrier[2])])
    
    cat("Now Starting",barrier,"\n")
    
    gcdist_km2<-gcdist_km[subset_locs,c(1,subset_locs+1)]
    gslFSTm2<-gslFSTm[subset_locs,c(1,subset_locs+1)]
    
    #######################################################################
    # 6. Create a dummy distance matrix for each putative "barrier" 
    #     between the two regions (1s and 0s)
    
    barrier_m2<-as.matrix(dist(as.numeric(locs2$VeronDivis %in% barrier[1])))
    
    barrier_m2 <- cbind(sample=locs2$sample,as.data.frame(barrier_m2))
    
    #if there aren't enough samples on either side of this barrier, then record this as non testable and go to next barrier
    if(Numpops1+Numpops2 < 3){cat("Less than three sampled populations; not testable\n"); barriertests[k,]<-c(gsl,barrier[1],Numpops1,barrier[2],Numpops2,F,F);next}
    if( Numpops1 < 1) {cat("not enough populations within",barrier[1],"\n") ; barriertests[k,]<-c(gsl,barrier[1],Numpops1,barrier[2],Numpops2,F,F);next}
    if( Numpops2 < 1) {cat("not enough populations within",barrier[2],"\n") ; barriertests[k,]<-c(gsl,barrier[1],Numpops1,barrier[2],Numpops2,F,F);next}
    
    ############################################################################
    # 7. Run through gdm with the barrier and without. Save the deviance values.
    
    locs2$sample<-as.character(locs2$sample)
    gslFSTm2$sample<-as.character(gslFSTm2$sample)
    gcdist_km2$sample<-as.character(gcdist_km2$sample)
    
    gdm.format<-formatsitepair(bioData=gslFSTm2, bioFormat=3, predData=locs2[,1:3],XColumn = "decimalLongitude", YColumn = "decimalLatitude", siteColumn="sample", distPreds=list(gcdist_km2,barrier_m2))
    
     #zap population pairs with 0 geographical distance between them. Troubling.
    zaps<-which(gdm.format$s2.matrix_1==0)
    
    if(length(zaps)>0) {
    gdm.format<-gdm.format[-zaps,]
    }
    
    #run gdm with and without the barrier
    gdm.barrier<-gdm(gdm.format)
    gdm.no.barrier<-gdm(gdm.format[,-grep("matrix_2",names(gdm.format))])
    
    # run mrdm
    mrdm<-MRM(formula = distance ~ s2.matrix_1 + s2.matrix_2, data=gdm.format,nperm = 10000)
    
    #TROUBLESHOOTING: save fst matrices from gdm models that obtain no solution
    if(is.null(gdm.barrier) | is.null(gdm.no.barrier))
      {cat("No Solution Obtained \n");
      nosolution[[paste(gsl,barrier[1],Numpops1,barrier[2],Numpops2,sep=",")]]<-list(locs2,gcdist_km2,gslFSTm2,gdm.format);
      barriertests[k,]<-c(gsl,barrier[1],Numpops1,barrier[2],Numpops2,T,F);
      next}
    
    #difference in deviance
    deltadev<-gdm.no.barrier$gdmdeviance-gdm.barrier$gdmdeviance
    
    #percent of null deviance explained by the model with just distance
    explaineddev<-gdm.no.barrier$explained
    
    ##############################################################################
    # 8. Perform Monte-Carlo permutations to develop a null distribution 
    #    of deviance values and determine significance (pvalue)
    gdm.format.rand<-gdm.format
    rand.deltas<-vector() 
    rand.explained<-vector()
    
    while(length(rand.deltas) < 1000) {
      gdm.format.rand$distance<-sample(gdm.format.rand$distance,size=length(gdm.format.rand$distance))
      gdm.barrier.rand<-gdm(gdm.format.rand)
      gdm.no.barrier.rand<-gdm(gdm.format.rand[,-grep("matrix_2",
                                                      names(gdm.format))])
      if(is.null(gdm.barrier.rand) | is.null(gdm.no.barrier.rand)){next}
      deltadev.rand<-gdm.no.barrier.rand$gdmdeviance-gdm.barrier.rand$gdmdeviance
      explained.rand<-gdm.no.barrier.rand$explained
      
      rand.deltas<-c(rand.deltas,deltadev.rand)
      rand.explained<-c(rand.explained,explained.rand)
    }
    pvalue_barrier<-length(which(abs(deltadev) < abs(rand.deltas)))/length(rand.deltas)
    pvalue_dist<-length(which(abs(explaineddev) < abs(rand.explained)))/length(rand.explained)
    
    cat("Good Solution \n")
    
    
    #save stats
    gdm.barrier.deviance<-gdm.barrier$gdmdeviance
    gdm.barrier.explained<-gdm.barrier$explained

    gdm.no.barrier.deviance<-gdm.no.barrier$gdmdeviance
    gdm.no.barrier.explained<-gdm.no.barrier$explained

    impt.dist.gdm.barrier<-sum(gdm.barrier$coefficients[1:gdm.barrier$splines[1]])
    impt.barrier.gdm.barrier<-sum(gdm.barrier$coefficients[gdm.barrier$splines[1]+1:gdm.barrier$splines[1]])
    impt.dist.gdm.no.barrier<-sum(gdm.no.barrier$coefficients[1:gdm.no.barrier$splines[1]])
    
    mrdm.rsquared<-mrdm$r.squared[1]
    mrdm.rsquared.pvalue<-mrdm$r.squared[2]
    mrdm.dist.pvalue<-mrdm$coef[2,2]
    mrdm.barrier.pvalue<-mrdm$coef[3,2]
    
    
   
    stats_model<-c(gsl,paste(barrier[1],barrier[2],sep="-"),gdm.barrier.deviance,gdm.barrier.explained, impt.dist.gdm.barrier, impt.barrier.gdm.barrier, gdm.no.barrier.deviance, gdm.no.barrier.explained,impt.dist.gdm.no.barrier, deltadev,pvalue_barrier,pvalue_dist,mrdm.rsquared,mrdm.rsquared.pvalue,mrdm.dist.pvalue,mrdm.barrier.pvalue)
    
    stats[nrow(stats)+1,]<-stats_model
    
    #record this in the table
    barriertests[k,]<-c(gsl,barrier[1],Numpops1,barrier[2],Numpops2,T,T)
    
  }
  




stats.full$GDM.regions.qvalue<-p.adjust(as.numeric(stats.full$Pvalue_regions),method="fdr")
stats.full$GDM.distance.qvalue<-p.adjust(as.numeric(stats.full$Pvalue_dist),method="fdr")

stats$GDM.qvalue<-p.adjust(as.numeric(stats$Pvalue_barrier),method="fdr")
stats$MRDM.r2.qvalue<-p.adjust(as.numeric(stats$MRDM.rsquared.pvalue),method="fdr")
stats$MRDM.dist.qvalue<-p.adjust(as.numeric(stats$MRDM.dist.pvalue),method="fdr")
stats$MRDM.barrier.qvalue<-p.adjust(as.numeric(stats$MRDM.barrier.pvalue),method="fdr")



# do some figuring with the results
length(barriertests[which(barriertests$Test==T),1])
#working GDM tests
length(barriertests[which(barriertests$Solution==T & barriertests$Test==T),1])
#failed GDM tests
length(barriertests[which(barriertests$Solution==F & barriertests$Test==T),1])



length(stats[which(stats$GDM.qvalue <= 0.02),1])

length(stats[which(stats$MRDM.barrier.qvalue <= 0.02),1])

#overlap between MRDM and GDM
length(stats[which(stats$GDM.qvalue <= 0.02 & stats$MRDM.barrier.qvalue <= 0.02),1])





goodbarriers<-stats %>% filter(GDM.qvalue < 0.02) %>% group_by(Barrier) %>% summarize(goodbarriers = n())

allbarriers<-stats %>% group_by(Barrier) %>% summarize(barrier_tests = n())

barrier_ratios<-left_join(allbarriers,goodbarriers,by="Barrier")

barrier_ratios$goodbarriers[which(is.na(barrier_ratios$goodbarriers))]<-0

barrier_ratios<-mutate(barrier_ratios, goodbarriers/barrier_tests)


kable(barrier_ratios)

write.csv(stats,"./output/GDM_output_WCTheta_1000reps.csv")
write.csv(barrier_ratios, "./output/GDM_JostD_WCTheta_barriers.csv")

Create a heatmap from GDM regions

dbRDA


# read in the Fst/PhiSt table 
load("~/google_drive/DIPnet_Gait_Lig_Bird/DIPnet_WG4_first_papers/statistics/By_Species/Pairwise_statistics/sample/DIPnet_structure_sample_WCTheta.Rdata")
#load("~/Desktop/DIPnet_structure_sample_PhiST_042817.Rdata")


##1. Dataframe for results
stats<-data.frame(Species_Locus=character(0),constrained.inertia=numeric(0),totalInertia=numeric(0),ProportionConstrained=numeric(0),adj.R2.total=numeric(0),modelF=numeric(0),modelPvalue=numeric(0),pcx_Var=numeric(0),pcx_p=numeric(0),pcy_Var=numeric(0),pcy_p=numeric(0),bestmodel=character(0), constrained.inertia.best=numeric(0), total.inertia.best=numeric(0), proportion.constrained.inertia.best=numeric(0), adj.R2.best.model=numeric(0), stringsAsFactors = F)
stats$Species_Locus<-as.character(stats$Species_Locus)
#stats$Barrier<-as.character(stats$Barrier)
stats$bestmodel<-as.character(stats$bestmodel)

# Make an empty list to save rda output for each species
esu_loci <- unique(ipdb$Genus_species_locus)
all.gsl.rda<-sapply(esu_loci, function(x) NULL)

#make empty data frames to save variance and pvalues
term.vars<-data.frame(gsl=character(0))
term.pvals<-data.frame(gsl=character(0))

###############################################################################
# 2. Subsample for each species of interest, and filter based on Phi_ST table.
for(gsl in esu_loci){ #gsl<-"Linckia_laevigata_CO1" "Tridacna_crocea_CO1" "Lutjanus_kasmira_CYB"
  
  cat("\n","\n","\n","Now starting", gsl, "\n")
  
  if(any(is.na(diffstats[[gsl]]))){cat("NAs in FST table, No dbRDA calculated"); next}
  
  if(diffstats[[gsl]]=="Fewer than 3 sampled populations after filtering. No stats calculated"){all.gsl.rda[[gsl]]<-"Fewer than 5 sampled populations after filtering."; cat("Fewer than 5 sampled populations after filtering.");next}
   sp<-ipdb[which(ipdb$Genus_species_locus==gsl),]
  
  #clean weird backslashes from names
  sp$locality<-gsub("\"","",sp$locality)
  
  sp$sample<-paste(sp$locality,round(sp$decimalLatitude, digits=0),round(sp$decimalLongitude, digits=0),sep="_")  #sets up a variable that matches the name in Fst table
  sp<-sp[order(sp$sample),]
  # Not all localities are included in Veron's regionalization (e.g. Guam), so get their names and then zap NAs
  nonVeronpops<-unique(sp$sample[is.na(sp$VeronDivis)])
  sp<-sp[!is.na(sp$VeronDivis),]
  
  #subsample Fst 
  gslFST<-diffstats[[gsl]]
  #make a matrix out of gslFST, convert negative values to zero
  gslFSTm<-as.matrix(gslFST)
  gslFSTm[which(gslFSTm<0)]<-0.0
  
  #zap weird slashes in the names
  rownames(gslFSTm)<-gsub("\"","",rownames(gslFSTm))
  colnames(gslFSTm)<-rownames(gslFSTm)
  
  #zap the same na populations from the list of non existent pops from VeronDivis
  if(any(rownames(gslFSTm) %in% nonVeronpops)){
    gslFSTm<-gslFSTm[-(which(rownames(gslFSTm) %in% nonVeronpops)),-(which(colnames(gslFSTm) %in% nonVeronpops))]
  }
  if(length(rownames(gslFSTm))<5){all.gsl.rda[[gsl]]<-"Fewer than 5 sampled populations";cat("Fewer than 5 sampled populations");next}
  
  #and filter sp based on the localities that have Fst values
  sp<-sp[sp$sample %in% rownames(gslFSTm),]
  
  #and vice versa
  
  gslFSTm<- gslFSTm[which(rownames(gslFSTm) %in% unique(sp$sample)),which(rownames(gslFSTm) %in% unique(sp$sample))]
  

  if(length(rownames(gslFSTm))<5){all.gsl.rda[[gsl]]<-"Fewer than 5 sampled populations";cat("Fewer than 5 sampled populations");next}
  
  #create a locations data frame that has all the localities plus lats and longs and their Veron region.
  locs<-as.data.frame(unique(sp$sample))
  names(locs)<-"sample"
  #locs$Long<-sp$decimalLongitude[which(locs %in% sp$sample)]
  #can't do a unique on sample, lats and longs because some samples have non-unique lats and longs! So I do a join and take the first match.
  locs<-join(locs,sp[c("sample","decimalLongitude","decimalLatitude"
                       ,"VeronDivis")], by="sample", match="first")
  if (length(unique(locs$VeronDivis)) < 2) {"Only one region!"; cat("Only one region!"); next}
  
  #sort gslFSTm
  gslFSTm<-gslFSTm[order(rownames(gslFSTm)),order(colnames(gslFSTm))]

  
  ######################################################################
  # 4. Calculate Great Circle Distance
  gcdist_km <- pointDistance(locs[,2:3],lonlat=T)/1000
  # and symmetricise it
  gcdist_km[upper.tri(gcdist_km)]<-0
  gcdist_km<-gcdist_km + t(gcdist_km)
   
  ####################################################################### Calculate Overwater Distances#
  #Save for later##

  ##############################################################################
  #5. Create a matrix of regional identities
  
  regions<-with(locs, data.frame(model.matrix(~VeronDivis+0)))   #one of the predictors is superfluous but will get knocked out during RDA
  row.names(regions)<-row.names(locs)
  

    ############################################################################
    # 7. Calculate the principal coordinates
    
    FST.pcoa<-cmdscale(gslFSTm, k=dim(as.matrix(gslFSTm))[1] - 1, eig=TRUE, add=FALSE) #ignore warnings - OK to have negatives according to Anderson
    FST.scores<-FST.pcoa$points
    
    gcdist.pcoa<-cmdscale(gcdist_km, k=2, eig=TRUE, add=FALSE)
    gcdist.scores<-gcdist.pcoa$points
    gcdist.scores<-data.frame("pcx"=gcdist.pcoa$points[,1],"pcy"=gcdist.pcoa$points[,2])
    locs2<-cbind(regions,gcdist.scores)
    
    ###########################################################################
    # 8. Calculate the RDA and extract statistics
    RDA.res<-rda(FST.scores~., data=locs2, scale=TRUE )
    
    #Extract Statistics
    constrained.inertia<-summary(RDA.res)$constr.chi
    total.inertia<-summary(RDA.res)$tot.chi
    proportion.constrained.inertia<-constrained.inertia/total.inertia
    
    adj.R2.total.model<-RsquareAdj(RDA.res)$adj.r.squared
    if(is.na(adj.R2.total.model)){cat("Predictors >= Observations! No solution");all.gsl.rda[[gsl]]<-"Predictors >= Observations! No solution";next}
    
    model.sig<-anova.cca(RDA.res, step=1000)
    modelF<-model.sig$F[1]
    modelPvalue<-model.sig$`Pr(>F)`[1]
    
    terms.sig<-anova(RDA.res, by="term", step=1000)
    pcx_Var<-terms.sig$Variance[1]
    pcx_p<-terms.sig$`Pr(>F)`[1]
    pcy_Var<-terms.sig$Variance[2]
    pcy_p<-terms.sig$`Pr(>F)`[2]
    
    #extract all variance values into a dataframe
    term.var<-as.data.frame(t(terms.sig[,2]))
    names(term.var)<-rownames(terms.sig)
   
    #extract all p-values into a dataframe
    term.pval<-as.data.frame(t(terms.sig[,4]))
    names(term.pval)<-rownames(terms.sig)
    
     
    # scale the variance
    term.var<-term.var/sum(term.var)
    
    # set variance to zero if it is not significant
    term.var[1,which(term.pval[1,] > 0.05 | is.na(term.pval[1,]))]<-0
    
    #set all values to zero if the model itself is not significant
    if(modelPvalue > 0.05){
    term.var[1,which(names(term.var)!="gsl")]<-0
    }
    # add on the species name
    term.pval$gsl<-gsl
    term.var$gsl<-gsl
    
    #merge them on to each dataframe
    term.vars<-merge(term.vars,term.var,all=T)
    term.pvals<-merge(term.pvals,term.pval,all=T)
    
    
    
    #barrier_Var<-terms.sig$Variance[3]   #omitting for now as the number of barriers will differ
    #barrier_p<-terms.sig$`Pr(>F)`[3]
    
    #marg.sig<-anova(RDA.res, by="margin", step=1000)
    #barrier_margVar<-marg.sig$Variance[3]
    #barrier_margp<-marg.sig$`Pr(>F)`[3]
    
    #Model selection
    nullmodel<-rda(FST.scores~1, data=locs2, scale=TRUE )
    forward.model<-ordiR2step(nullmodel, scope=formula(RDA.res), directon="forward", psteps=1000)  #ordiR2step implements Blanchets stopping criterion
    bestmodel<-as.character(forward.model$call[2])
    if (is.null(summary(forward.model)$constr.chi)) {
      constrained.inertia.best<-NA
      total.inertia.best<-summary(forward.model)$tot.chi
      proportion.constrained.inertia.best<-NA
      adj.R2.best.model<-NA
    } else {
      constrained.inertia.best<-summary(forward.model)$constr.chi
      total.inertia.best<-summary(forward.model)$tot.chi
      proportion.constrained.inertia.best<-constrained.inertia.best/total.inertia.best
      adj.R2.best.model<-RsquareAdj(forward.model)$adj.r.squared
    }
     
  
    #save stats
    
    stats_model<-c(gsl,constrained.inertia,total.inertia,proportion.constrained.inertia,adj.R2.total.model,modelF,modelPvalue,pcx_Var,pcx_p,pcy_Var,pcy_p, bestmodel, constrained.inertia.best, total.inertia.best, proportion.constrained.inertia.best, adj.R2.best.model)
    
    stats[nrow(stats)+1,]<-stats_model
    all.gsl.rda[[gsl]]<-RDA.res
    
    
 
  }

write.csv(term.vars,file="./output/dbRDA_term_vars_WCTHETA.csv")
write.csv(term.pvals,file="./output/dbRDA_term_pvals_WCTHETA.csv")

 save(all.gsl.rda,file="./output/multibarrier_dbRDA_WCTHETA.Rdata")
  
write.csv(stats, "./output/multibarrier_dbRDA_JOSTD.csv")
  

Make a heatmap of the variance values

LS0tCnRpdGxlOiAiRElQbmV0IFBvcHVsYXRpb24gU3RydWN0dXJlIE5vdGVib29rIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwotLS0KCiMgU2V0dXAKYGBge3IgU2V0dXAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoc2VxaW5yKQpsaWJyYXJ5KGFwZSkgIApsaWJyYXJ5KHBlZ2FzKQpsaWJyYXJ5KGhpZXJmc3RhdCkKbGlicmFyeShtbW9kKQpsaWJyYXJ5KGFkZWdlbmV0KQpsaWJyYXJ5KHBseXIpCmxpYnJhcnkoc3RyYXRhRykKbGlicmFyeShpTkVYVCkKbGlicmFyeShnZG0pCmxpYnJhcnkoZ2Rpc3RhbmNlKQpsaWJyYXJ5KGVjb2Rpc3QpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocmVzaGFwZTIpCmxpYnJhcnkoV3JpdGVYTFMpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShrbml0cikKbGlicmFyeSh2ZWdhbikKCgpzb3VyY2UoImNvbmZpZy5SIikKc291cmNlKCJESVBuZXRfU3RhdHNfRnVuY3Rpb25zLlIiKQoKcmVzY2FsZTwtZnVuY3Rpb24oeCl7CiAgbm9ybWFsaXplZDwtKHgtbWluKHgpKS8obWF4KHgpLW1pbih4KSkKICByZXR1cm4obm9ybWFsaXplZCkKfQoKYGBgCgpgYGB7ciBJbXBvcnQgRGF0YX0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIDEuIEltcG9ydCB0aGUgSVBEQiBhbmQgRnN0IHRhYmxlcwppcGRiPC1yZWFkLnRhYmxlKGlwZGJfcGF0aCxzZXA9Ilx0IixoZWFkZXI9VCxzdHJpbmdzQXNGYWN0b3JzID0gRixxdW90ZT0iIiwgbmEuc3RyaW5ncz1jKCJOQSIsIiAiLCIiKSkgCgoKI3JlYWQgaW4gZ2VvZ3JhcGhpY2FsIHJlZ2lvbmFsaXphdGlvbnMgZnJvbSBUcmVtbApzcGF0aWFsPC1yZWFkLnRhYmxlKHNwYXRpYWxfcGF0aCwgaGVhZGVyPVQsIHNlcD0iXHQiLHN0cmluZ3NBc0ZhY3RvcnMgPSBGLCBuYS5zdHJpbmdzPWMoIk5BIiwiICIsIiIpLCBxdW90ZT0iIikKCiNyZWFkIGluIGdlb2dyYXBoaWNhbCByZWdpb25hbGl6YXRpb25zIGZyb20gQmVnZXIKc3BhdGlhbDI8LXJlYWQudGFibGUoc3BhdGlhbDJfcGF0aCwgaGVhZGVyPVQsc2VwPSJcdCIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGLCBuYS5zdHJpbmdzPWMoIk5BIiwiICIsIiIpLCBxdW90ZT0iIikKCiNyZWFkIGluIEFCR0QgZ3JvdXBzCmFiZ2Q8LXJlYWQudGFibGUoYWJnZF9wYXRoLCBoZWFkZXI9VCwgc2VwPSJcdCIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKI2pvaW4gc3BhdGlhbAppcGRiPC1qb2luKGlwZGIsc3BhdGlhbCwgYnkgPSAiSVBEQl9JRCIsdHlwZSA9ICJsZWZ0IikKaXBkYjwtam9pbihpcGRiLHNwYXRpYWwyWyxjKDIsMTg6MjQpXSwgYnkgPSAiSVBEQl9JRCIsIHR5cGUgPSAibGVmdCIpCgojam9pbiBBQkdECmlwZGI8LWpvaW4oaXBkYixhYmdkWyxjKDEsMyldLCBieSA9ICJJUERCX0lEIix0eXBlID0gImxlZnQiKQoKIyBkcm9wIGh5YnJpZHMgYW5kIGRpdmVyZ2VudCBpbmRpdmlkdWFscwppcGRiPC1pcGRiW2lwZGIkSVBEQl9JRCAlaW4lIGRyb3BzID09IEZBTFNFLCBdIAoKCgojIyByZW1vdmUgYW55dGhpbmcgbm90IGluY2x1ZGVkIGluIHRoZSBlY29yZWdpb25zIHNjaGVtZSAoc29tZSBkb2xwaGlucywgc29tZSBDT1RTIGZyb20gS2luZ21hbiBhbmQgTWFkYWdhc2Nhcig/KSwgc29tZSBBLiBuaWdyb3MgZnJvbSBLaXJpYmF0aSwgc29tIEMuIGF1cmlnYSBmcm9tIEZha2FyZXZhLCBoYW1tZXJoZWFkcyBmcm9tIFdlc3Rlcm4gQXVzdHJhbGlhLCBhbmQgV2VzdCBBZnJpY2EsIGFuZCBzb21lIGRvbHBoaW5zIGZyb20gdGhlIG1pZGRsZSBvZiB0aGUgZWFzdGVybiB0cm9waWNhbCBwYWNpZmljCgppcGRiX2Vjb3JlZ2lvbnM8LWlwZGJbLXdoaWNoKGlzLm5hKGlwZGIkRUNPUkVHSU9OKSksXQoKIyMgcmVtb3ZlIGFueXRoaW5nIHRoYXQgZG9lc24ndCBvY2N1ciBpbiB0aGUgMyBJbmRvLVBhY2lmaWMgcmVhbG1zCmlwZGJfaXA8LWlwZGJfZWNvcmVnaW9uc1t3aGljaChpcGRiX2Vjb3JlZ2lvbnMkUkVBTE0gJWluJSBjKCJDZW50cmFsIEluZG8tUGFjaWZpYyIsIldlc3Rlcm4gSW5kby1QYWNpZmljIiwiRWFzdGVybiBJbmRvLVBhY2lmaWMiKSksXQoKYW1vdmFfdHNfcGF0aDwtIi9Vc2Vycy9lcmljL2dvb2dsZV9kcml2ZS9ESVBuZXRfR2FpdF9MaWdfQmlyZC9ESVBuZXRfV0c0X2ZpcnN0X3BhcGVycy9zdGF0aXN0aWNzL0J5X1NwZWNpZXMvSGllcmFyY2hpY2FsX3N0cnVjdHVyZSIKCmFtb3ZhX2FiZ2RfcGF0aDwtIi9Vc2Vycy9lcmljL2dvb2dsZV9kcml2ZS9ESVBuZXRfR2FpdF9MaWdfQmlyZC9ESVBuZXRfV0c0X2ZpcnN0X3BhcGVycy9zdGF0aXN0aWNzL0J5X0VTVS9IaWVyYXJjaGljYWxfc3RydWN0dXJlIgoKIyBSZWFkIGluIFZlcm9uIGJhcnJpZXJzCmJhcnJpZXJzPC1yZWFkLmNzdigiVmVyb25CYXJyaWVycy5jc3YiLGhlYWRlcj1GLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKCgpgYGAKCgojIEludHJvZHVjdGlvbgoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIEkgYW0gdHJ5aW5nIGl0IG91dCBhcyBhIHdheSB0byByZXByb2R1Y2libHkgZG9jdW1lbnQgbXkgd29yayBvbiB0aGUgRElQbmV0IFBvcHVsYXRpb24gU3RydWN0dXJlIFBhcGVyLgoKVGhlIG92ZXJhbGwgd29ya2Zsb3cgZm9yIHRoaXMgYW5hbHlzaXMgaXMgYXMgZm9sbG93czoKCiAgLSBSdW4gQU1PVkEgYWNjb3JkaW5nIHRvIHNldmVyYWwgZGlmZmVyZW50IHJlZ2lvbmFsaXphdGlvbnMKICAgIC0gQnJpZ2dzIGFuZCBCb3dlbiAyMDEzIC0gRmlzaCBCaW9nZW9ncmFwaHkKICAgIC0gVmVyb24gZXQgYWwuIDIwMTUgLSBDb3JhbCBCaW9nZW9ncmFwaHkKICAgIC0gU3BhbGRpbmcgZXQgYWwuIDIwMDcgLSAKICAgICAgICAtIE1hcmluZSBFY29yZWdpb25zCiAgICAgICAgLSBQcm92aW5jZXMKICAgICAgICAtIFJlYWxtcwogICAgLSBLdWxiaWNraSBldCBhbC4gMjAxMyAtIAogICAgICAgIC0gUmVnaW9uYWxpemF0aW9uIGJhc2VkIG9uIGFsbCBzcGVjaWVzLCAKICAgICAgICAtIG9yIGp1c3QgInJlbGlhYmxlIiBzcGVjaWVzCiAgICAtIEtlaXRoIGV0IGFsLiAyMDEzIC0gRmF1bmFsIEJyZWFrcwogIC0gU2VsZWN0IHRoZSBiZXN0IG1vZGVsIGZvciBlYWNoIHNwZWNpZXMgYWNjb3JkaW5nIHRvIHRoZSBCYXllc2lhbiBJbmZvcm1hdGlvbiBDcml0ZXJpb24KICAtIEFuYWx5emUgaW5kaXZpZHVhbCAiYmFycmllcnMiIGFzIGltcGxpZWQgYnkgdGhlIHJlZ2lvbmFsaXphdGlvbiB0aGF0IGJlc3QgZXhwbGFpbnMgdGhlIGRpc3RyaWJ1dGlvbiBvZiB2YXJpYXRpb24gaW4gdGhlIG1vc3Qgc3BlY2llcyBieSBtb2RlbGluZyBwYWlyd2lzZSBnZW5ldGljIGRpc3RhbmNlcyBnaXZlbiBnZW9ncmFwaGljIGRpc3RhbmNlIGFuZCBlYWNoIGJhcnJpZXIgKGluZGl2aWR1YWxseSBvciB0b2dldGhlcik6CiAgICAtIEdlbmVyYWxpemVkIERpc3NpbWlsYXJpdHkgTW9kZWxpbmcgKEdETSkKICAgIC0gTXVsdGlwbGUgUmVncmVzc2lvbiB3aXRoIERpc3RhbmNlIE1hdHJpY2VzIChNUkRNKQogICAgLSBEaXN0YW5jZSBCYXNlZCBSZWR1bmRhbmN5IEFuYWx5c2lzIChkYlJEQSkKICAtIFNwZWNpYWwgY29uc2lkZXJhdGlvbnM6CiAgICAtIFdoYXQgaXMgYSBzcGVjaWVzPyBEbyB0aGUgYW5hbHlzaXMgdXNpbmc6CiAgICAgICAgLSBUcmFkaXRpb25hbCBzcGVjaWVzIGJvdW5kYXJpZXMKICAgICAgICAtIEF1dG9tYXRlZCBCYXJjb2RlIEdhcCBEaXNjb3ZlcnkgKEFCR0QpIHRvIGFjY291bnQgZm9yIGNyeXB0aWMgc3BlY2llcwogICAgLSBJbmNsdWRlIHNlcXVlbmNlIGRpc3RhbmNlIGluIEFNT1ZBPwogICAgICAgIC0gTm86IHRyYWRpdGlvbmFsIEZzdCwgc3BlY2lmaWNhbGx5IFdlaXIgYW5kIENvY2tlcmhhbXMgVGhldGEKICAgICAgICAtIFllczogUGhpLVNUCgojIFJ1biBBTU9WQSBsb29wcwoKR2l2ZW4gdGhlIHNwZWNpYWwgY29uc2lkZXJhdGlvbnMsIHdlIG5lZWQgdG8gcnVuIDQgZGlmZmVyZW50IGZsYXZvcnMgb2YgQU1PVkE6CiAgMS4gV0NUaGV0YSBhbmQgVHJhZFNwZWMKICAyLiBXQ1RoZXRhIGFuZCBBQkdECiAgMy4gUGhpU1QgYW5kIFRyYWRTcGVjCiAgNC4gUGhpU1QgYW5kIEFCR0QKClRodXMsIHdlIG5lZWQgdG8gbG9vcCB0aHJvdWdoIGFsbCBvZiB0aGUgcmVnaW9uYWxpemF0aW9ucyBhYm92ZSwgcnVubmluZyBhbGwgNCBmbGF2b3JzIG9mIEFNT1ZBLgoKCmBgYHtyIEFNT1ZBIExvb3BzLCBldmFsPUZ9CgojIyBMb29wIHRocm91Z2ggaHlwb3RoZXNlcywgY2FsY3VsYXRpbmcgQU1PVkEKaHlwb3RoZXNlczwtYygiRUNPUkVHSU9OIiwgIlBST1ZJTkNFIiwiUkVBTE0iLCJCb3dlbiIsIktlaXRoIiwiS3VsYmlja2lfciIsIkt1bGJpY2tpX2IiLCAiVmVyb25EaXZpcyIpCmFtb3ZhX2xpc3Q8LWxpc3QoKQoKZm9yKGggaW4gaHlwb3RoZXNlcyl7CiAgaGllcnN0YXRzPC1oaWVyYXJjaGljYWwuc3RydWN0dXJlLm10RE5BLmRiKGlwZGIgPSBpcGRiX2lwLGxldmVsMSA9ICJzYW1wbGUiLGxldmVsMj1oLG1vZGVsPSJub25lIixBQkdEPUYsbnBlcm09MSkKICBhbW92YV9saXN0W1toXV08LWhpZXJzdGF0cwp9CiAgCgojIyBTdW1tYXJpemUgQU1PVkEgcmVzdWx0cwphbW92YXN0YXRzPC1zdW1tYXJpemVfQU1PVkEoYW1vdmFfbGlzdCxoeXBvdGhlc2VzLHNwZWNpZXNsaXN0PXVuaXF1ZShpcGRiJEdlbnVzX3NwZWNpZXNfbG9jdXMpKQoKV3JpdGVYTFMoYW1vdmFzdGF0cyxFeGNlbEZpbGVOYW1lPWZpbGUucGF0aChhbW92YV90c19wYXRoLCJGU1RfVHJhZFNwZWNfcmF3X2Ftb3ZhX291dHB1dC5SZGF0YS54bHN4IikpCnNhdmUoYW1vdmFfbGlzdCxmaWxlPWZpbGUucGF0aChhbW92YV90c19wYXRoLCJGU1RfVHJhZFNwZWNfcmF3X2Ftb3ZhX291dHB1dC5SZGF0YSIpKQpzYXZlKGFtb3Zhc3RhdHMsZmlsZT1maWxlLnBhdGgoYW1vdmFfdHNfcGF0aCwiRlNUX1RyYWRTcGVjX3RhYmxlX2Ftb3ZhX291dHB1dC5SZGF0YSIpKQpgYGAKCgpUaGlzIHRha2VzIGEgbG9uZyB0aW1lLCBzbyB3ZSBhcmUgbm90IHJ1bm5pbmcgdGhpcyBjb2RlIGluIHRoZSBkb2N1bWVudCwgYnV0IGxvYWRpbmcgaW4gdGhlIHJlc3VsdHMgYXMgd2UgZ28gdGhyb3VnaCBlYWNoIGNvbnNpZGVyYXRpb24KCiMgVmlzdWFsaXplIEFNT1ZBIHJlc3VsdHMKCiMjIEZTVCBhbmQgVHJhZGl0aW9uYWwgU3BlY2llcyBCb3VuZGFyaWVzCgojIyMgTWVhc3VyZSBTdXBwb3J0CmBgYHtyIE1lYXN1cmUgU3VwcG9ydDF9CmxvYWQoZmlsZT1maWxlLnBhdGgoYW1vdmFfdHNfcGF0aCwiRlNUX1RyYWRTcGVjX3RhYmxlX2Ftb3ZhX291dHB1dC5SZGF0YSIpKQoKIyBNZWFzdXJlIHN1cHBvcnQgZm9yIGVhY2ggaHlwb3RoZXNpcwoKI0dldCB0aGUgdmFsdWVzIGZvciBlYWNoIGh5cG90aGVzaXMgZm9yIGEgZ2l2ZW4gY3JpdGVyaW9uIC0gaGVyZSBJIHVzZSBCSUMgLSBhbmQgcmFuayB0aGVtIGZvciAjZWFjaCBzcGVjaWVzLCB0aGVuIGNob29zZSB0aGUgImJlc3QiIGh5cG90aGVzaXMgZm9yIGVhY2ggc3BlY2llcyBiYXNlZCBvbiB0aGUgY3JpdGVyaW9uLgoKY3JpdGVyaW9uPC0iQklDIgojIGZpbmQgdGhlIG1heGltdW0gbnVtYmVyIG9mIHNwZWNpZXMgZnJvbSBhbnkgb2YgdGhlIDggaHlwb3RoZXNlcwptYXhsZW5ndGg8LW1heChzYXBwbHkoYW1vdmFzdGF0cyxmdW5jdGlvbih4KSBsZW5ndGgoeFtbMV1dKSkpIAojIGNyZWF0ZSBhbiBlbXB0eSBkYXRhIGZyYW1lIHdpdGggcm93IG5hbWVzIGZyb20gdGhlIGh5cG90aGVzaXMgd2l0aCB0aGUgbW9zdCB2YWx1ZXMKY3JpdF9kZjwtZGF0YS5mcmFtZShzZXROYW1lcyhyZXBsaWNhdGUobWF4bGVuZ3RoLG51bWVyaWMoMCksIHNpbXBsaWZ5ID0gRiksbm09cm93Lm5hbWVzKGFtb3Zhc3RhdHNbWyJQUk9WSU5DRSJdXSkpKSAKCiNMb29wIHRocm91Z2ggdGhlIGh5cG90aGVzZXMsIHB1bGxpbmcgb3V0IHRoZSB2YWx1ZXMgZm9yIGNyaXRlcmlvbix0cmFuc3Bvc2UgaXQsIGFuZCB0aGVuIG1lcmdlIHRoZXNlIHZhbHVlcyBpbnRvIHRoZSBkYXRhZnJhbWUgZnJvbSB0aGUgcHJldmlvdXMgaHlwb3RoZXNpcyAKZm9yKGggaW4gbmFtZXMoYW1vdmFzdGF0cykpewogIGNyaXRfZGY8LW1lcmdlKGNyaXRfZGYsdChhbW92YXN0YXRzW1toXV1bY3JpdGVyaW9uXSksYWxsPVQsc29ydD1GKQp9CiNnZXQgdGhlIGh5cG90aGVzaXMgbmFtZXMgaW4gdGhlcmUKcm93Lm5hbWVzKGNyaXRfZGYpPC1uYW1lcyhhbW92YXN0YXRzKQoKI3JhbmsgdGhlIGh5cG90aGVzZXMgZm9yIGVhY2ggc3BlY2llcwpjcml0X3Jhbms8LWFzLmRhdGEuZnJhbWUoc2FwcGx5KGNyaXRfZGYscmFuayxuYS5sYXN0PSJrZWVwIix0aWVzLm1ldGhvZD0iYXZlcmFnZSIpKQpyb3cubmFtZXMoY3JpdF9yYW5rKTwtbmFtZXMoYW1vdmFzdGF0cykKCiMjIHJlbW92ZSBnc2xzIHdpdGggbW9yZSB0aGFuIDMgbWlzc2luZyBtb2RlbHMKY3JpdF9yYW5rPC1jcml0X3JhbmtbLCBjb2xTdW1zKGlzLm5hKGNyaXRfcmFuaykpIDwgbnJvdyhjcml0X3JhbmspLTVdICAKCiMjIGNob29zZSB0aGUgYmVzdCBoeXBvdGhlc2lzIG9yIHNldCBvZiBoeXBvdGhlc2VzIGZvciBlYWNoIHNwZWNpZXMgIApiZXN0X2h5cG90aGVzaXM8LXNhcHBseShjcml0X3JhbmssZnVuY3Rpb24oeCl7cm93Lm5hbWVzKGNyaXRfcmFuaylbd2hpY2goeD09bWluKHgsbmEucm09VCkpIF19KQoKCiMjIE1ha2UgYSBiYXIgZ3JhcGggb2YgYmVzdCBzdXBwb3J0IGZvciBlYWNoIGh5cG90aGVzaXMgYW1vbmcgc3BlY2llcwoKYmFycGxvdDwtZ2dwbG90KGRhdGE9YXMuZGF0YS5mcmFtZSh1bmxpc3QoYmVzdF9oeXBvdGhlc2lzKSksIGFlcyh4PXVubGlzdChiZXN0X2h5cG90aGVzaXMpICkpICsgZ2VvbV9iYXIoYWVzKHkgPSAoLi5jb3VudC4uKS9zdW0oLi5jb3VudC4uKSkpICsgbGFicyh4PSJIeXBvdGhlc2lzIix5PSJQcm9wb3J0aW9uIG9mIFNwZWNpZXMiLCB0aXRsZT0iUHJvcG9ydGlvbmFsIFN1cHBvcnQgZm9yIEJpb2dlb2dyYXBoaWMgSHlwb3RoZXNlcyBiYXNlZCBvbiBCSUMiKQoKYmFycGxvdApgYGAKCiMjIyBDYWxjdWxhdGUgcmVsYXRpdmUgcHJvYmFiaWxpdHkgZnJvbSBKb2huc29uIGFuZCBPbWxhbmQgMjAwNCBhbmQgdmlzdWFsaXplIHdpdGggYSBoZWF0bWFwCmBgYHtyIFJlbGF0aXZlIFByb2JhYmlsaXR5IEhlYXRtYXAxLCBmaWcuaGVpZ2h0PTExLCBmaWcud2lkdGg9OC41fQojIGxvb2t1cCB0aGUgbWluaW11bSBCSUMgdmFsdWUgZm9yIGVhY2ggc3BlY2llcyAod2hpY2gubWluIHdvcmtzIGJldHRlciBoZXJlLCBiZWNhdXNlIGl0IHJldHVybnMgb25seSB0aGUgZmlyc3QgaW5zdGFuY2Ugb2YgdGhlIG1pbmltdW0gdmFsdWUpCm1pbkJJQzwtc2FwcGx5KGNyaXRfZGYsZnVuY3Rpb24oeCl7eFt3aGljaC5taW4oeCldfSkgCgojSiZPIGJveCA0IGVxbiAxLiBzY2FsZSgpIHNlZW1zIHRvIGJlIHRoZSB3YXkgdG8gZ28gaGVyZSwgdXNpbmcgdGhlIG1pbkJJQyBhcyB0aGUgY2VudGVyaW5nIHZlY3Rvcgpjcml0X2RmX2RlbHRhSTwtc2NhbGUoY3JpdF9kZiwgY2VudGVyPW1pbkJJQywgc2NhbGU9RikgCgojSiZPIGJveCA0IGVxbiA0LiBudW1lcmF0b3IsIHBsdXMgbWFrZSBpdCBhIGRhdGEgZnJhbWUKY3JpdF9kZl9kZWx0YUlfYjwtYXMuZGF0YS5mcmFtZShleHAoLTAuNSpjcml0X2RmX2RlbHRhSSkpIAoKI0omTyBib3ggNCBlcW4gNC4gZGVub21pbmF0b3IKY3JpdF9kZl9kZWx0YUlfc3Vtczwtc2FwcGx5KGNyaXRfZGZfZGVsdGFJX2Isc3VtLG5hLnJtPVQpIAoKIyB0aGlzIHRpbWUgdXNlIHRoZSBzY2FsZSBhcmd1bWVudCBvZiBzY2FsZSB0byBkaXZpZGUgZWFjaCBjb2x1bW4gYnkgdGhlIGNvcnJlc3BvbmRpbmcgc3VtCmNyaXRfZGZfcmVsYXRpdmVfcHJvYjwtc2NhbGUoY3JpdF9kZl9kZWx0YUlfYixjZW50ZXI9RixzY2FsZT1jcml0X2RmX2RlbHRhSV9zdW1zKSAKCgojIyBNYWtlIGEgaGVhdG1hcCBvZiByZWxhdGl2ZSBwcm9iYWJpbGl0eSBvZiBlYWNoIGh5cG90aGVzaXMKCiNtZWx0IGZvciBnZ3Bsb3QyCnJlbHByb2I8LW1lbHQoY3JpdF9kZl9yZWxhdGl2ZV9wcm9iKQpjb2xuYW1lcyhyZWxwcm9iKTwtYygiSHlwb3RoZXNpcyIsIlNwZWNpZXMiLCJSZWxhdGl2ZV9Qcm9iYWJpbGl0eSIpCgojYmFzZXBsb3QKcnA8LWdncGxvdChyZWxwcm9iLGFlcyh5PVNwZWNpZXMseD1IeXBvdGhlc2lzLGZpbGw9UmVsYXRpdmVfUHJvYmFiaWxpdHkpKQoKI2FkZCBnZW9tX3RpbGUsIHR1cm4gdGhlIHgtYXhpcyBlbGVtZW50cyBieSA5MCBkZWdyZWVzLCByZXZlcnNlIHRoZSBuYW1lcyBvbiB0aGUgeS1heGlzLCBhbmQgdXNlIGEgZGl2ZXJnaW5nIGNvbG9yIHNjaGVtZSB0byBoaWdobGlnaHQgaHlwb3RoZXNlcyB3aXRoID41MCUgcmVsIHByb2IuCnJwPC1ycCtnZW9tX3RpbGUoKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSsKICB5bGltKHJldihsZXZlbHMocmVscHJvYiRTcGVjaWVzKSkpKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgbWlkID0gIndoaXRlIiwKICAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gInJlZCIsIG1pZHBvaW50ID0gMC41LCBzcGFjZSA9ICJyZ2IiLAogICAgICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gImdyZXk1MCIsIGd1aWRlID0gImNvbG91cmJhciIpCnJwCmBgYAoKCiMjIFBISVNUIGFuZCBUcmFkaXRpb25hbCBTcGVjaWVzIEJvdW5kYXJpZXMKCkNvZGUgaXMgc3VwcHJlc3NlZCBmb3IgdGhlIG90aGVyIDMgZXhhbXBsZXMKCiMjIyBNZWFzdXJlIFN1cHBvcnQKYGBge3IgTWVhc3VyZSBTdXBwb3J0MiwgZWNobz1GfQpsb2FkKGZpbGU9ZmlsZS5wYXRoKGFtb3ZhX3RzX3BhdGgsIlBISVNUX1RyYWRTcGVjaWVzX3RhYmxlX2Ftb3ZhX291dHB1dC5SZGF0YSIpKQoKIyBNZWFzdXJlIHN1cHBvcnQgZm9yIGVhY2ggaHlwb3RoZXNpcwoKI0dldCB0aGUgdmFsdWVzIGZvciBlYWNoIGh5cG90aGVzaXMgZm9yIGEgZ2l2ZW4gY3JpdGVyaW9uIC0gaGVyZSBJIHVzZSBCSUMgLSBhbmQgcmFuayB0aGVtIGZvciAjZWFjaCBzcGVjaWVzLCB0aGVuIGNob29zZSB0aGUgImJlc3QiIGh5cG90aGVzaXMgZm9yIGVhY2ggc3BlY2llcyBiYXNlZCBvbiB0aGUgY3JpdGVyaW9uLgoKY3JpdGVyaW9uPC0iQklDIgojIGZpbmQgdGhlIG1heGltdW0gbnVtYmVyIG9mIHNwZWNpZXMgZnJvbSBhbnkgb2YgdGhlIDggaHlwb3RoZXNlcwptYXhsZW5ndGg8LW1heChzYXBwbHkoYW1vdmFzdGF0cyxmdW5jdGlvbih4KSBsZW5ndGgoeFtbMV1dKSkpIAojIGNyZWF0ZSBhbiBlbXB0eSBkYXRhIGZyYW1lIHdpdGggcm93IG5hbWVzIGZyb20gdGhlIGh5cG90aGVzaXMgd2l0aCB0aGUgbW9zdCB2YWx1ZXMKY3JpdF9kZjwtZGF0YS5mcmFtZShzZXROYW1lcyhyZXBsaWNhdGUobWF4bGVuZ3RoLG51bWVyaWMoMCksIHNpbXBsaWZ5ID0gRiksbm09cm93Lm5hbWVzKGFtb3Zhc3RhdHNbWyJQUk9WSU5DRSJdXSkpKSAKCiNMb29wIHRocm91Z2ggdGhlIGh5cG90aGVzZXMsIHB1bGxpbmcgb3V0IHRoZSB2YWx1ZXMgZm9yIGNyaXRlcmlvbix0cmFuc3Bvc2UgaXQsIGFuZCB0aGVuIG1lcmdlIHRoZXNlIHZhbHVlcyBpbnRvIHRoZSBkYXRhZnJhbWUgZnJvbSB0aGUgcHJldmlvdXMgaHlwb3RoZXNpcyAKZm9yKGggaW4gbmFtZXMoYW1vdmFzdGF0cykpewogIGNyaXRfZGY8LW1lcmdlKGNyaXRfZGYsdChhbW92YXN0YXRzW1toXV1bY3JpdGVyaW9uXSksYWxsPVQsc29ydD1GKQp9CiNnZXQgdGhlIGh5cG90aGVzaXMgbmFtZXMgaW4gdGhlcmUKcm93Lm5hbWVzKGNyaXRfZGYpPC1uYW1lcyhhbW92YXN0YXRzKQoKI3JhbmsgdGhlIGh5cG90aGVzZXMgZm9yIGVhY2ggc3BlY2llcwpjcml0X3Jhbms8LWFzLmRhdGEuZnJhbWUoc2FwcGx5KGNyaXRfZGYscmFuayxuYS5sYXN0PSJrZWVwIix0aWVzLm1ldGhvZD0iYXZlcmFnZSIpKQpyb3cubmFtZXMoY3JpdF9yYW5rKTwtbmFtZXMoYW1vdmFzdGF0cykKCiMjIHJlbW92ZSBnc2xzIHdpdGggbW9yZSB0aGFuIDMgbWlzc2luZyBtb2RlbHMKY3JpdF9yYW5rPC1jcml0X3JhbmtbLCBjb2xTdW1zKGlzLm5hKGNyaXRfcmFuaykpIDwgbnJvdyhjcml0X3JhbmspLTVdICAKCiMjIGNob29zZSB0aGUgYmVzdCBoeXBvdGhlc2lzIG9yIHNldCBvZiBoeXBvdGhlc2VzIGZvciBlYWNoIHNwZWNpZXMgIApiZXN0X2h5cG90aGVzaXM8LXNhcHBseShjcml0X3JhbmssZnVuY3Rpb24oeCl7cm93Lm5hbWVzKGNyaXRfcmFuaylbd2hpY2goeD09bWluKHgsbmEucm09VCkpIF19KQoKCiMjIE1ha2UgYSBiYXIgZ3JhcGggb2YgYmVzdCBzdXBwb3J0IGZvciBlYWNoIGh5cG90aGVzaXMgYW1vbmcgc3BlY2llcwoKYmFycGxvdDwtZ2dwbG90KGRhdGE9YXMuZGF0YS5mcmFtZSh1bmxpc3QoYmVzdF9oeXBvdGhlc2lzKSksIGFlcyh4PXVubGlzdChiZXN0X2h5cG90aGVzaXMpICkpICsgZ2VvbV9iYXIoYWVzKHkgPSAoLi5jb3VudC4uKS9zdW0oLi5jb3VudC4uKSkpICsgbGFicyh4PSJIeXBvdGhlc2lzIix5PSJQcm9wb3J0aW9uIG9mIFNwZWNpZXMiLCB0aXRsZT0iUHJvcG9ydGlvbmFsIFN1cHBvcnQgZm9yIEJpb2dlb2dyYXBoaWMgSHlwb3RoZXNlcyBiYXNlZCBvbiBCSUMiKQoKYmFycGxvdApgYGAKCgojIyMgQ2FsY3VsYXRlIHJlbGF0aXZlIHByb2JhYmlsaXR5IGZyb20gSm9obnNvbiBhbmQgT21sYW5kIDIwMDQgYW5kIHZpc3VhbGl6ZSB3aXRoIGEgaGVhdG1hcApgYGB7ciBSZWxhdGl2ZSBQcm9iYWJpbGl0eSBIZWF0bWFwMiwgZWNobz1GfQojIGxvb2t1cCB0aGUgbWluaW11bSBCSUMgdmFsdWUgZm9yIGVhY2ggc3BlY2llcyAod2hpY2gubWluIHdvcmtzIGJldHRlciBoZXJlLCBiZWNhdXNlIGl0IHJldHVybnMgb25seSB0aGUgZmlyc3QgaW5zdGFuY2Ugb2YgdGhlIG1pbmltdW0gdmFsdWUpCm1pbkJJQzwtc2FwcGx5KGNyaXRfZGYsZnVuY3Rpb24oeCl7eFt3aGljaC5taW4oeCldfSkgCgojSiZPIGJveCA0IGVxbiAxLiBzY2FsZSgpIHNlZW1zIHRvIGJlIHRoZSB3YXkgdG8gZ28gaGVyZSwgdXNpbmcgdGhlIG1pbkJJQyBhcyB0aGUgY2VudGVyaW5nIHZlY3Rvcgpjcml0X2RmX2RlbHRhSTwtc2NhbGUoY3JpdF9kZiwgY2VudGVyPW1pbkJJQywgc2NhbGU9RikgCgojSiZPIGJveCA0IGVxbiA0LiBudW1lcmF0b3IsIHBsdXMgbWFrZSBpdCBhIGRhdGEgZnJhbWUKY3JpdF9kZl9kZWx0YUlfYjwtYXMuZGF0YS5mcmFtZShleHAoLTAuNSpjcml0X2RmX2RlbHRhSSkpIAoKI0omTyBib3ggNCBlcW4gNC4gZGVub21pbmF0b3IKY3JpdF9kZl9kZWx0YUlfc3Vtczwtc2FwcGx5KGNyaXRfZGZfZGVsdGFJX2Isc3VtLG5hLnJtPVQpIAoKIyB0aGlzIHRpbWUgdXNlIHRoZSBzY2FsZSBhcmd1bWVudCBvZiBzY2FsZSB0byBkaXZpZGUgZWFjaCBjb2x1bW4gYnkgdGhlIGNvcnJlc3BvbmRpbmcgc3VtCmNyaXRfZGZfcmVsYXRpdmVfcHJvYjwtc2NhbGUoY3JpdF9kZl9kZWx0YUlfYixjZW50ZXI9RixzY2FsZT1jcml0X2RmX2RlbHRhSV9zdW1zKSAKCgojIyBNYWtlIGEgaGVhdG1hcCBvZiByZWxhdGl2ZSBwcm9iYWJpbGl0eSBvZiBlYWNoIGh5cG90aGVzaXMKCiNtZWx0IGZvciBnZ3Bsb3QyCnJlbHByb2I8LW1lbHQoY3JpdF9kZl9yZWxhdGl2ZV9wcm9iKQpjb2xuYW1lcyhyZWxwcm9iKTwtYygiSHlwb3RoZXNpcyIsIlNwZWNpZXMiLCJSZWxhdGl2ZV9Qcm9iYWJpbGl0eSIpCgojYmFzZXBsb3QKcnA8LWdncGxvdChyZWxwcm9iLGFlcyh5PVNwZWNpZXMseD1IeXBvdGhlc2lzLGZpbGw9UmVsYXRpdmVfUHJvYmFiaWxpdHkpKQoKI2FkZCBnZW9tX3RpbGUsIHR1cm4gdGhlIHgtYXhpcyBlbGVtZW50cyBieSA5MCBkZWdyZWVzLCByZXZlcnNlIHRoZSBuYW1lcyBvbiB0aGUgeS1heGlzLCBhbmQgdXNlIGEgZGl2ZXJnaW5nIGNvbG9yIHNjaGVtZSB0byBoaWdobGlnaHQgaHlwb3RoZXNlcyB3aXRoID41MCUgcmVsIHByb2IuCnJwPC1ycCtnZW9tX3RpbGUoKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSsKICB5bGltKHJldihsZXZlbHMocmVscHJvYiRTcGVjaWVzKSkpKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgbWlkID0gIndoaXRlIiwKICAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gInJlZCIsIG1pZHBvaW50ID0gMC41LCBzcGFjZSA9ICJyZ2IiLAogICAgICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gImdyZXk1MCIsIGd1aWRlID0gImNvbG91cmJhciIpCnJwCmBgYAojIyBGU1QgYW5kIEFCR0QgQm91bmRhcmllcwoKIyMjIE1lYXN1cmUgU3VwcG9ydApgYGB7ciBNZWFzdXJlIFN1cHBvcnQzLCBlY2hvPUZ9CmxvYWQoZmlsZT1maWxlLnBhdGgoYW1vdmFfYWJnZF9wYXRoLCJGU1RfQUJHRF90YWJsZV9hbW92YV9vdXRwdXQuUmRhdGEiKSkKCiMgTWVhc3VyZSBzdXBwb3J0IGZvciBlYWNoIGh5cG90aGVzaXMKCiNHZXQgdGhlIHZhbHVlcyBmb3IgZWFjaCBoeXBvdGhlc2lzIGZvciBhIGdpdmVuIGNyaXRlcmlvbiAtIGhlcmUgSSB1c2UgQklDIC0gYW5kIHJhbmsgdGhlbSBmb3IgI2VhY2ggc3BlY2llcywgdGhlbiBjaG9vc2UgdGhlICJiZXN0IiBoeXBvdGhlc2lzIGZvciBlYWNoIHNwZWNpZXMgYmFzZWQgb24gdGhlIGNyaXRlcmlvbi4KCmNyaXRlcmlvbjwtIkJJQyIKIyBmaW5kIHRoZSBtYXhpbXVtIG51bWJlciBvZiBzcGVjaWVzIGZyb20gYW55IG9mIHRoZSA4IGh5cG90aGVzZXMKbWF4bGVuZ3RoPC1tYXgoc2FwcGx5KGFtb3Zhc3RhdHMsZnVuY3Rpb24oeCkgbGVuZ3RoKHhbWzFdXSkpKSAKIyBjcmVhdGUgYW4gZW1wdHkgZGF0YSBmcmFtZSB3aXRoIHJvdyBuYW1lcyBmcm9tIHRoZSBoeXBvdGhlc2lzIHdpdGggdGhlIG1vc3QgdmFsdWVzCmNyaXRfZGY8LWRhdGEuZnJhbWUoc2V0TmFtZXMocmVwbGljYXRlKG1heGxlbmd0aCxudW1lcmljKDApLCBzaW1wbGlmeSA9IEYpLG5tPXJvdy5uYW1lcyhhbW92YXN0YXRzW1siUFJPVklOQ0UiXV0pKSkgCgojTG9vcCB0aHJvdWdoIHRoZSBoeXBvdGhlc2VzLCBwdWxsaW5nIG91dCB0aGUgdmFsdWVzIGZvciBjcml0ZXJpb24sdHJhbnNwb3NlIGl0LCBhbmQgdGhlbiBtZXJnZSB0aGVzZSB2YWx1ZXMgaW50byB0aGUgZGF0YWZyYW1lIGZyb20gdGhlIHByZXZpb3VzIGh5cG90aGVzaXMgCmZvcihoIGluIG5hbWVzKGFtb3Zhc3RhdHMpKXsKICBjcml0X2RmPC1tZXJnZShjcml0X2RmLHQoYW1vdmFzdGF0c1tbaF1dW2NyaXRlcmlvbl0pLGFsbD1ULHNvcnQ9RikKfQojZ2V0IHRoZSBoeXBvdGhlc2lzIG5hbWVzIGluIHRoZXJlCnJvdy5uYW1lcyhjcml0X2RmKTwtbmFtZXMoYW1vdmFzdGF0cykKCiNyYW5rIHRoZSBoeXBvdGhlc2VzIGZvciBlYWNoIHNwZWNpZXMKY3JpdF9yYW5rPC1hcy5kYXRhLmZyYW1lKHNhcHBseShjcml0X2RmLHJhbmssbmEubGFzdD0ia2VlcCIsdGllcy5tZXRob2Q9ImF2ZXJhZ2UiKSkKcm93Lm5hbWVzKGNyaXRfcmFuayk8LW5hbWVzKGFtb3Zhc3RhdHMpCgojIyByZW1vdmUgZ3NscyB3aXRoIG1vcmUgdGhhbiAzIG1pc3NpbmcgbW9kZWxzCmNyaXRfcmFuazwtY3JpdF9yYW5rWywgY29sU3Vtcyhpcy5uYShjcml0X3JhbmspKSA8IG5yb3coY3JpdF9yYW5rKS01XSAgCgojIyBjaG9vc2UgdGhlIGJlc3QgaHlwb3RoZXNpcyBvciBzZXQgb2YgaHlwb3RoZXNlcyBmb3IgZWFjaCBzcGVjaWVzICAKYmVzdF9oeXBvdGhlc2lzPC1zYXBwbHkoY3JpdF9yYW5rLGZ1bmN0aW9uKHgpe3Jvdy5uYW1lcyhjcml0X3JhbmspW3doaWNoKHg9PW1pbih4LG5hLnJtPVQpKSBdfSkKCgojIyBNYWtlIGEgYmFyIGdyYXBoIG9mIGJlc3Qgc3VwcG9ydCBmb3IgZWFjaCBoeXBvdGhlc2lzIGFtb25nIHNwZWNpZXMKCmJhcnBsb3Q8LWdncGxvdChkYXRhPWFzLmRhdGEuZnJhbWUodW5saXN0KGJlc3RfaHlwb3RoZXNpcykpLCBhZXMoeD11bmxpc3QoYmVzdF9oeXBvdGhlc2lzKSApKSArIGdlb21fYmFyKGFlcyh5ID0gKC4uY291bnQuLikvc3VtKC4uY291bnQuLikpKSArIGxhYnMoeD0iSHlwb3RoZXNpcyIseT0iUHJvcG9ydGlvbiBvZiBTcGVjaWVzIiwgdGl0bGU9IlByb3BvcnRpb25hbCBTdXBwb3J0IGZvciBCaW9nZW9ncmFwaGljIEh5cG90aGVzZXMgYmFzZWQgb24gQklDIikKCmJhcnBsb3QKYGBgCgoKIyMjIENhbGN1bGF0ZSByZWxhdGl2ZSBwcm9iYWJpbGl0eSBmcm9tIEpvaG5zb24gYW5kIE9tbGFuZCAyMDA0IGFuZCB2aXN1YWxpemUgd2l0aCBhIGhlYXRtYXAKYGBge3IgUmVsYXRpdmUgUHJvYmFiaWxpdHkgSGVhdG1hcDMsIGVjaG89Rn0KIyBsb29rdXAgdGhlIG1pbmltdW0gQklDIHZhbHVlIGZvciBlYWNoIHNwZWNpZXMgKHdoaWNoLm1pbiB3b3JrcyBiZXR0ZXIgaGVyZSwgYmVjYXVzZSBpdCByZXR1cm5zIG9ubHkgdGhlIGZpcnN0IGluc3RhbmNlIG9mIHRoZSBtaW5pbXVtIHZhbHVlKQptaW5CSUM8LXNhcHBseShjcml0X2RmLGZ1bmN0aW9uKHgpe3hbd2hpY2gubWluKHgpXX0pIAoKI0omTyBib3ggNCBlcW4gMS4gc2NhbGUoKSBzZWVtcyB0byBiZSB0aGUgd2F5IHRvIGdvIGhlcmUsIHVzaW5nIHRoZSBtaW5CSUMgYXMgdGhlIGNlbnRlcmluZyB2ZWN0b3IKY3JpdF9kZl9kZWx0YUk8LXNjYWxlKGNyaXRfZGYsIGNlbnRlcj1taW5CSUMsIHNjYWxlPUYpIAoKI0omTyBib3ggNCBlcW4gNC4gbnVtZXJhdG9yLCBwbHVzIG1ha2UgaXQgYSBkYXRhIGZyYW1lCmNyaXRfZGZfZGVsdGFJX2I8LWFzLmRhdGEuZnJhbWUoZXhwKC0wLjUqY3JpdF9kZl9kZWx0YUkpKSAKCiNKJk8gYm94IDQgZXFuIDQuIGRlbm9taW5hdG9yCmNyaXRfZGZfZGVsdGFJX3N1bXM8LXNhcHBseShjcml0X2RmX2RlbHRhSV9iLHN1bSxuYS5ybT1UKSAKCiMgdGhpcyB0aW1lIHVzZSB0aGUgc2NhbGUgYXJndW1lbnQgb2Ygc2NhbGUgdG8gZGl2aWRlIGVhY2ggY29sdW1uIGJ5IHRoZSBjb3JyZXNwb25kaW5nIHN1bQpjcml0X2RmX3JlbGF0aXZlX3Byb2I8LXNjYWxlKGNyaXRfZGZfZGVsdGFJX2IsY2VudGVyPUYsc2NhbGU9Y3JpdF9kZl9kZWx0YUlfc3VtcykgCgoKIyMgTWFrZSBhIGhlYXRtYXAgb2YgcmVsYXRpdmUgcHJvYmFiaWxpdHkgb2YgZWFjaCBoeXBvdGhlc2lzCgojbWVsdCBmb3IgZ2dwbG90MgpyZWxwcm9iPC1tZWx0KGNyaXRfZGZfcmVsYXRpdmVfcHJvYikKY29sbmFtZXMocmVscHJvYik8LWMoIkh5cG90aGVzaXMiLCJTcGVjaWVzIiwiUmVsYXRpdmVfUHJvYmFiaWxpdHkiKQoKI2Jhc2VwbG90CnJwPC1nZ3Bsb3QocmVscHJvYixhZXMoeT1TcGVjaWVzLHg9SHlwb3RoZXNpcyxmaWxsPVJlbGF0aXZlX1Byb2JhYmlsaXR5KSkKCiNhZGQgZ2VvbV90aWxlLCB0dXJuIHRoZSB4LWF4aXMgZWxlbWVudHMgYnkgOTAgZGVncmVlcywgcmV2ZXJzZSB0aGUgbmFtZXMgb24gdGhlIHktYXhpcywgYW5kIHVzZSBhIGRpdmVyZ2luZyBjb2xvciBzY2hlbWUgdG8gaGlnaGxpZ2h0IGh5cG90aGVzZXMgd2l0aCA+NTAlIHJlbCBwcm9iLgpycDwtcnArZ2VvbV90aWxlKCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkrCiAgeWxpbShyZXYobGV2ZWxzKHJlbHByb2IkU3BlY2llcykpKSsKICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIG1pZCA9ICJ3aGl0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgaGlnaCA9ICJyZWQiLCBtaWRwb2ludCA9IDAuNSwgc3BhY2UgPSAicmdiIiwKICAgICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9ICJncmV5NTAiLCBndWlkZSA9ICJjb2xvdXJiYXIiKQpycApgYGAKCiMjIFBISVNUIGFuZCBBQkdEIEJvdW5kYXJpZXMKCiMjIyBNZWFzdXJlIFN1cHBvcnQKYGBge3IgTWVhc3VyZSBTdXBwb3J0NCwgZWNobz1GfQpsb2FkKGZpbGU9ZmlsZS5wYXRoKGFtb3ZhX2FiZ2RfcGF0aCwiUEhJU1RfQUJHRF90YWJsZV9hbW92YV9vdXRwdXQuUmRhdGEiKSkKCiMgTWVhc3VyZSBzdXBwb3J0IGZvciBlYWNoIGh5cG90aGVzaXMKCiNHZXQgdGhlIHZhbHVlcyBmb3IgZWFjaCBoeXBvdGhlc2lzIGZvciBhIGdpdmVuIGNyaXRlcmlvbiAtIGhlcmUgSSB1c2UgQklDIC0gYW5kIHJhbmsgdGhlbSBmb3IgI2VhY2ggc3BlY2llcywgdGhlbiBjaG9vc2UgdGhlICJiZXN0IiBoeXBvdGhlc2lzIGZvciBlYWNoIHNwZWNpZXMgYmFzZWQgb24gdGhlIGNyaXRlcmlvbi4KCmNyaXRlcmlvbjwtIkJJQyIKIyBmaW5kIHRoZSBtYXhpbXVtIG51bWJlciBvZiBzcGVjaWVzIGZyb20gYW55IG9mIHRoZSA4IGh5cG90aGVzZXMKbWF4bGVuZ3RoPC1tYXgoc2FwcGx5KGFtb3Zhc3RhdHMsZnVuY3Rpb24oeCkgbGVuZ3RoKHhbWzFdXSkpKSAKIyBjcmVhdGUgYW4gZW1wdHkgZGF0YSBmcmFtZSB3aXRoIHJvdyBuYW1lcyBmcm9tIHRoZSBoeXBvdGhlc2lzIHdpdGggdGhlIG1vc3QgdmFsdWVzCmNyaXRfZGY8LWRhdGEuZnJhbWUoc2V0TmFtZXMocmVwbGljYXRlKG1heGxlbmd0aCxudW1lcmljKDApLCBzaW1wbGlmeSA9IEYpLG5tPXJvdy5uYW1lcyhhbW92YXN0YXRzW1siUFJPVklOQ0UiXV0pKSkgCgojTG9vcCB0aHJvdWdoIHRoZSBoeXBvdGhlc2VzLCBwdWxsaW5nIG91dCB0aGUgdmFsdWVzIGZvciBjcml0ZXJpb24sdHJhbnNwb3NlIGl0LCBhbmQgdGhlbiBtZXJnZSB0aGVzZSB2YWx1ZXMgaW50byB0aGUgZGF0YWZyYW1lIGZyb20gdGhlIHByZXZpb3VzIGh5cG90aGVzaXMgCmZvcihoIGluIG5hbWVzKGFtb3Zhc3RhdHMpKXsKICBjcml0X2RmPC1tZXJnZShjcml0X2RmLHQoYW1vdmFzdGF0c1tbaF1dW2NyaXRlcmlvbl0pLGFsbD1ULHNvcnQ9RikKfQojZ2V0IHRoZSBoeXBvdGhlc2lzIG5hbWVzIGluIHRoZXJlCnJvdy5uYW1lcyhjcml0X2RmKTwtbmFtZXMoYW1vdmFzdGF0cykKCiNyYW5rIHRoZSBoeXBvdGhlc2VzIGZvciBlYWNoIHNwZWNpZXMKY3JpdF9yYW5rPC1hcy5kYXRhLmZyYW1lKHNhcHBseShjcml0X2RmLHJhbmssbmEubGFzdD0ia2VlcCIsdGllcy5tZXRob2Q9ImF2ZXJhZ2UiKSkKcm93Lm5hbWVzKGNyaXRfcmFuayk8LW5hbWVzKGFtb3Zhc3RhdHMpCgojIyByZW1vdmUgZ3NscyB3aXRoIG1vcmUgdGhhbiAzIG1pc3NpbmcgbW9kZWxzCmNyaXRfcmFuazwtY3JpdF9yYW5rWywgY29sU3Vtcyhpcy5uYShjcml0X3JhbmspKSA8IG5yb3coY3JpdF9yYW5rKS01XSAgCgojIyBjaG9vc2UgdGhlIGJlc3QgaHlwb3RoZXNpcyBvciBzZXQgb2YgaHlwb3RoZXNlcyBmb3IgZWFjaCBzcGVjaWVzICAKYmVzdF9oeXBvdGhlc2lzPC1zYXBwbHkoY3JpdF9yYW5rLGZ1bmN0aW9uKHgpe3Jvdy5uYW1lcyhjcml0X3JhbmspW3doaWNoKHg9PW1pbih4LG5hLnJtPVQpKSBdfSkKCgojIyBNYWtlIGEgYmFyIGdyYXBoIG9mIGJlc3Qgc3VwcG9ydCBmb3IgZWFjaCBoeXBvdGhlc2lzIGFtb25nIHNwZWNpZXMKCmJhcnBsb3Q8LWdncGxvdChkYXRhPWFzLmRhdGEuZnJhbWUodW5saXN0KGJlc3RfaHlwb3RoZXNpcykpLCBhZXMoeD11bmxpc3QoYmVzdF9oeXBvdGhlc2lzKSApKSArIGdlb21fYmFyKGFlcyh5ID0gKC4uY291bnQuLikvc3VtKC4uY291bnQuLikpKSArIGxhYnMoeD0iSHlwb3RoZXNpcyIseT0iUHJvcG9ydGlvbiBvZiBTcGVjaWVzIiwgdGl0bGU9IlByb3BvcnRpb25hbCBTdXBwb3J0IGZvciBCaW9nZW9ncmFwaGljIEh5cG90aGVzZXMgYmFzZWQgb24gQklDIikKCmJhcnBsb3QKYGBgCgoKIyMjIENhbGN1bGF0ZSByZWxhdGl2ZSBwcm9iYWJpbGl0eSBmcm9tIEpvaG5zb24gYW5kIE9tbGFuZCAyMDA0IGFuZCB2aXN1YWxpemUgd2l0aCBhIGhlYXRtYXAKYGBge3IgUmVsYXRpdmUgUHJvYmFiaWxpdHkgSGVhdG1hcDQsIGVjaG89Rn0KIyBsb29rdXAgdGhlIG1pbmltdW0gQklDIHZhbHVlIGZvciBlYWNoIHNwZWNpZXMgKHdoaWNoLm1pbiB3b3JrcyBiZXR0ZXIgaGVyZSwgYmVjYXVzZSBpdCByZXR1cm5zIG9ubHkgdGhlIGZpcnN0IGluc3RhbmNlIG9mIHRoZSBtaW5pbXVtIHZhbHVlKQptaW5CSUM8LXNhcHBseShjcml0X2RmLGZ1bmN0aW9uKHgpe3hbd2hpY2gubWluKHgpXX0pIAoKI0omTyBib3ggNCBlcW4gMS4gc2NhbGUoKSBzZWVtcyB0byBiZSB0aGUgd2F5IHRvIGdvIGhlcmUsIHVzaW5nIHRoZSBtaW5CSUMgYXMgdGhlIGNlbnRlcmluZyB2ZWN0b3IKY3JpdF9kZl9kZWx0YUk8LXNjYWxlKGNyaXRfZGYsIGNlbnRlcj1taW5CSUMsIHNjYWxlPUYpIAoKI0omTyBib3ggNCBlcW4gNC4gbnVtZXJhdG9yLCBwbHVzIG1ha2UgaXQgYSBkYXRhIGZyYW1lCmNyaXRfZGZfZGVsdGFJX2I8LWFzLmRhdGEuZnJhbWUoZXhwKC0wLjUqY3JpdF9kZl9kZWx0YUkpKSAKCiNKJk8gYm94IDQgZXFuIDQuIGRlbm9taW5hdG9yCmNyaXRfZGZfZGVsdGFJX3N1bXM8LXNhcHBseShjcml0X2RmX2RlbHRhSV9iLHN1bSxuYS5ybT1UKSAKCiMgdGhpcyB0aW1lIHVzZSB0aGUgc2NhbGUgYXJndW1lbnQgb2Ygc2NhbGUgdG8gZGl2aWRlIGVhY2ggY29sdW1uIGJ5IHRoZSBjb3JyZXNwb25kaW5nIHN1bQpjcml0X2RmX3JlbGF0aXZlX3Byb2I8LXNjYWxlKGNyaXRfZGZfZGVsdGFJX2IsY2VudGVyPUYsc2NhbGU9Y3JpdF9kZl9kZWx0YUlfc3VtcykgCgoKIyMgTWFrZSBhIGhlYXRtYXAgb2YgcmVsYXRpdmUgcHJvYmFiaWxpdHkgb2YgZWFjaCBoeXBvdGhlc2lzCgojbWVsdCBmb3IgZ2dwbG90MgpyZWxwcm9iPC1tZWx0KGNyaXRfZGZfcmVsYXRpdmVfcHJvYikKY29sbmFtZXMocmVscHJvYik8LWMoIkh5cG90aGVzaXMiLCJTcGVjaWVzIiwiUmVsYXRpdmVfUHJvYmFiaWxpdHkiKQoKI2Jhc2VwbG90CnJwPC1nZ3Bsb3QocmVscHJvYixhZXMoeT1TcGVjaWVzLHg9SHlwb3RoZXNpcyxmaWxsPVJlbGF0aXZlX1Byb2JhYmlsaXR5KSkKCiNhZGQgZ2VvbV90aWxlLCB0dXJuIHRoZSB4LWF4aXMgZWxlbWVudHMgYnkgOTAgZGVncmVlcywgcmV2ZXJzZSB0aGUgbmFtZXMgb24gdGhlIHktYXhpcywgYW5kIHVzZSBhIGRpdmVyZ2luZyBjb2xvciBzY2hlbWUgdG8gaGlnaGxpZ2h0IGh5cG90aGVzZXMgd2l0aCA+NTAlIHJlbCBwcm9iLgpycDwtcnArZ2VvbV90aWxlKCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkrCiAgeWxpbShyZXYobGV2ZWxzKHJlbHByb2IkU3BlY2llcykpKSsKICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIG1pZCA9ICJ3aGl0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgaGlnaCA9ICJyZWQiLCBtaWRwb2ludCA9IDAuNSwgc3BhY2UgPSAicmdiIiwKICAgICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9ICJncmV5NTAiLCBndWlkZSA9ICJjb2xvdXJiYXIiKQpycApgYGAKCiMgQ2FsY3VsYXRlIFBhaXJ3aXNlIERpZmZlcmVudGlhdGlvbiBTdGF0cwoKQnkgc2FtcGxlCgpgYGB7ciwgZXZhbD1GfQpkaWZmc3RhdHM8LXBhaXJ3aXNlLnN0cnVjdHVyZS5tdEROQS5kYihpcGRiPWlwZGIsIGdkaXN0ID0gIldDIFRoZXRhIiwgbWluc2VxcyA9IDUsIG1pbnNhbXBzID0gMywgbWludG90YWxzZXFzID0gMCwgbnJlcCA9IDAsIG51bS5jb3JlcyA9IDIsIEFCR0QgPSBULCByZWdpb25hbGl6YXRpb24gPSAic2FtcGxlIikKCgpzYXZlKGRpZmZzdGF0cywgZmlsZT0iL1VzZXJzL2VyaWMvZ29vZ2xlX2RyaXZlL0RJUG5ldF9HYWl0X0xpZ19CaXJkL0RJUG5ldF9XRzRfZmlyc3RfcGFwZXJzL3N0YXRpc3RpY3MvQnlfRVNVL1BhaXJ3aXNlX3N0YXRpc3RpY3MvRElQbmV0X3N0cnVjdHVyZV9zYW1wbGVfV0NUaGV0YV9BQkdELlJkYXRhIikKCmRpZmZzdGF0czwtcGFpcndpc2Uuc3RydWN0dXJlLm10RE5BLmRiKGlwZGI9aXBkYiwgZ2Rpc3QgPSAiSm9zdCBEIiwgbWluc2VxcyA9IDUsIG1pbnNhbXBzID0gMywgbWludG90YWxzZXFzID0gMCwgbnJlcCA9IDAsIG51bS5jb3JlcyA9IDIsIEFCR0QgPSBULCByZWdpb25hbGl6YXRpb24gPSAic2FtcGxlIikKCgpzYXZlKGRpZmZzdGF0cywgZmlsZT0iL1VzZXJzL2VyaWMvZ29vZ2xlX2RyaXZlL0RJUG5ldF9HYWl0X0xpZ19CaXJkL0RJUG5ldF9XRzRfZmlyc3RfcGFwZXJzL3N0YXRpc3RpY3MvQnlfRVNVL1BhaXJ3aXNlX3N0YXRpc3RpY3MvRElQbmV0X3N0cnVjdHVyZV9zYW1wbGVfSm9zdERfQUJHRC5SZGF0YSIpCmBgYAoKIyBHZW5lcmFsaXplZCBEaXNzaW1pbGFyaXR5IE1vZGVsaW5nCgojIyBUcmFkaXRpb25hbCBTcGVjaWVzIEJvdW5kYXJpZXMKYGBge3IgR0RNMSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiAgbG9hZCgiL1VzZXJzL2VyaWMvZ29vZ2xlX2RyaXZlL0RJUG5ldF9HYWl0X0xpZ19CaXJkL0RJUG5ldF9XRzRfZmlyc3RfcGFwZXJzL3N0YXRpc3RpY3MvQnlfU3BlY2llcy9QYWlyd2lzZV9zdGF0aXN0aWNzL3NhbXBsZS9ESVBuZXRfc3RydWN0dXJlX3NhbXBsZV9XQ1RIRVRBLlJkYXRhIikKCmVzdV9sb2NpIDwtIHVuaXF1ZShpcGRiJEdlbnVzX3NwZWNpZXNfbG9jdXMpCgpnZG0uZnVsbDwtbGlzdCgpCgpzb2x1dGlvbjwtbGlzdCgpCm5vc29sdXRpb248LWxpc3QoKQpub3NvbHV0aW9uLmZ1bGw8LWxpc3QoKQoKc3RhdHMuZnVsbDwtZGF0YS5mcmFtZShTcGVjaWVzX0xvY3VzPWNoYXJhY3RlcigwKSxXaXRoUmVnaW9uc0RldmlhbmNlPW51bWVyaWMoMCksV2l0aFJlZ2lvbnNFeHBsYWluZWREZXZpYW5jZT1udW1lcmljKDApLE5vUmVnaW9uc0RldmlhbmNlPW51bWVyaWMoMCksTm9SZWdpb25zRXhwbGFpbmVkRGV2aWFuY2U9bnVtZXJpYygwKSxEZWx0YURldmlhbmNlPW51bWVyaWMoMCksUHZhbHVlX3JlZ2lvbnM9bnVtZXJpYygwKSxQdmFsdWVfZGlzdD1udW1lcmljKDApLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKc3RhdHM8LWRhdGEuZnJhbWUoU3BlY2llc19Mb2N1cz1jaGFyYWN0ZXIoMCksQmFycmllcj1jaGFyYWN0ZXIoMCksV2l0aEJhcnJpZXJEZXZpYW5jZT1udW1lcmljKDApLFdpdGhCYXJyaWVyRXhwbGFpbmVkRGV2aWFuY2U9bnVtZXJpYygwKSxJbXBvcnRhbmNlRGlzdGFuY2VXaXRoQmFycmllcj1udW1lcmljKDApLEltcG9ydGFuY2VCYXJyaWVyV2l0aEJhcnJpZXI9bnVtZXJpYygwKSxOb0JhcnJpZXJEZXZpYW5jZT1udW1lcmljKDApLE5vQmFycmllckV4cGxhaW5lZERldmlhbmNlPW51bWVyaWMoMCksSW1wb3J0YW5jZURpc3RhbmNlV2l0aG91dEJhcnJpZXI9bnVtZXJpYygwKSxEZWx0YURldmlhbmNlPW51bWVyaWMoMCksUHZhbHVlX2JhcnJpZXI9bnVtZXJpYygwKSxQdmFsdWVfZGlzdD1udW1lcmljKDApLE1SRE0ucnNxdWFyZWQ9bnVtZXJpYygwKSxNUkRNLnJzcXVhcmVkLnB2YWx1ZT1udW1lcmljKDApLE1SRE0uZGlzdC5wdmFsdWU9bnVtZXJpYygwKSwgTVJETS5iYXJyaWVyLnB2YWx1ZT1udW1lcmljKDApLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKbm9zdGF0czwtTlVMTAoKYmFycmllcnRlc3RzPC1kYXRhLmZyYW1lKFNwZWNpZXM9Y2hhcmFjdGVyKDApLFJlZ2lvbjE9Y2hhcmFjdGVyKDApLE51bVBvcHMxPW51bWVyaWMoMCksUmVnaW9uMj1jaGFyYWN0ZXIoMCksTnVtcG9wczI9bnVtZXJpYygwKSwgVGVzdD1sb2dpY2FsKDApLCBTb2x1dGlvbj1sb2dpY2FsKDApLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKazwtMAoKZm9yKGdzbCBpbiBlc3VfbG9jaSl7ICNnc2w8LSJMaW5ja2lhX2xhZXZpZ2F0YV9DTzEiICJUcmlkYWNuYV9jcm9jZWFfQ08xIiAiTHV0amFudXNfa2FzbWlyYV9DWUIiICJBY2FudGhhc3Rlcl9wbGFuY2lfQ08xIgogIAogIGNhdCgiXG4iLCJcbiIsIlxuIiwiTm93IHN0YXJ0aW5nIiwgZ3NsLCAiXG4iKQogIAogIGlmKGFueShpcy5uYShkaWZmc3RhdHNbW2dzbF1dKSkpe2NhdCgiTkFzIGluIEZTVCB0YWJsZSwgTm8gZ2RtIGNhbGN1bGF0ZWQiKTsgbmV4dH0KICAKICBpZihkaWZmc3RhdHNbW2dzbF1dPT0iRmV3ZXIgdGhhbiAzIHNhbXBsZWQgcG9wdWxhdGlvbnMgYWZ0ZXIgZmlsdGVyaW5nLiBObyBzdGF0cyBjYWxjdWxhdGVkIil7bm9zdGF0czwtYyhub3N0YXRzLGdzbCk7bmV4dH0KICAKICAjcHVsbCBvdXQgdGhlIGRhdGEgZm9yIHRoaXMgZ2VudXMtc3BlY2llcy1sb2N1cyAoZ3NsKQogIHNwPC1pcGRiW3doaWNoKGlwZGIkR2VudXNfc3BlY2llc19sb2N1cz09Z3NsKSxdCiAgI2NsZWFuIHdlaXJkIGJhY2tzbGFzaGVzIGZyb20gbmFtZXMKICBzcCRsb2NhbGl0eTwtZ3N1YigiXCIiLCIiLHNwJGxvY2FsaXR5KQogIAogIHNwJHNhbXBsZTwtcGFzdGUoc3AkbG9jYWxpdHkscm91bmQoc3AkZGVjaW1hbExhdGl0dWRlLCBkaWdpdHM9MCkscm91bmQoc3AkZGVjaW1hbExvbmdpdHVkZSwgZGlnaXRzPTApLHNlcD0iXyIpICAjc2V0cyB1cCBhIHZhcmlhYmxlIHRoYXQgbWF0Y2hlcyB0aGUgbmFtZSBpbiBGc3QgdGFibGUKICBzcDwtc3Bbb3JkZXIoc3Akc2FtcGxlKSxdCiAgIyBOb3QgYWxsIGxvY2FsaXRpZXMgYXJlIGluY2x1ZGVkIGluIFZlcm9uJ3MgcmVnaW9uYWxpemF0aW9uIChlLmcuIEd1YW0pLCBzbyBnZXQgdGhlaXIgbmFtZXMgYW5kIHRoZW4gemFwIE5BcwogIG5vblZlcm9ucG9wczwtdW5pcXVlKHNwJHNhbXBsZVtpcy5uYShzcCRWZXJvbkRpdmlzKV0pCiAgc3A8LXNwWyFpcy5uYShzcCRWZXJvbkRpdmlzKSxdCiAgCiAgI3N1YnNhbXBsZSBGc3QgCiAgZ3NsRlNUPC1kaWZmc3RhdHNbW2dzbF1dCiAgI21ha2UgYSBtYXRyaXggb3V0IG9mIGdzbEZTVAogIGdzbEZTVG08LWFzLm1hdHJpeChnc2xGU1QpCiAgCiAgZ3NsRlNUbVt3aGljaChnc2xGU1RtID4gMSldIDwtIDEgI3NvbWUgdmFsdWVzIHRoYXQgbG9vayBsaWtlIDEuMDAwMCBhcmUgcmVnaXN0ZXJpbmcgYXMgZ3JlYXRlciB0aGFuIDEKICBnc2xGU1RtW3doaWNoKGdzbEZTVG0gPCAwKV0gPC0gMC4wMDAxICNnZXQgcmlkIG9mIGFydGlmYWN0dWFsIG5lZ2F0aXZlIHZhbHVlcwogICNnc2xGU1RtPC1yZXNjYWxlKGdzbEZTVG0pCiAgI2dzbEZTVG08LWdzbEZTVG0vKDEtZ3NsRlNUbSkKICAKICAjemFwIHdlaXJkIHNsYXNoZXMgaW4gdGhlIG5hbWVzCiAgcm93bmFtZXMoZ3NsRlNUbSk8LWdzdWIoIlwiIiwiIixyb3duYW1lcyhnc2xGU1RtKSkKICBjb2xuYW1lcyhnc2xGU1RtKTwtcm93bmFtZXMoZ3NsRlNUbSkKICAKICAjemFwIHRoZSBzYW1lIG5hIHBvcHVsYXRpb25zIGZyb20gdGhlIGxpc3Qgb2Ygbm9uIGV4aXN0ZW50IHBvcHMgZnJvbSBWZXJvbkRpdmlzCiAgaWYoYW55KHJvd25hbWVzKGdzbEZTVG0pICVpbiUgbm9uVmVyb25wb3BzKSl7CiAgICBnc2xGU1RtPC1nc2xGU1RtWy0od2hpY2gocm93bmFtZXMoZ3NsRlNUbSkgJWluJSBub25WZXJvbnBvcHMpKSwtKHdoaWNoKGNvbG5hbWVzKGdzbEZTVG0pICVpbiUgbm9uVmVyb25wb3BzKSldCiAgfQogIAogIGlmKGxlbmd0aChyb3duYW1lcyhnc2xGU1RtKSk8NSl7bm9zdGF0czwtYyhub3N0YXRzLGdzbCk7Y2F0KCJGZXdlciB0aGFuIDUgc2FtcGxlZCBwb3B1bGF0aW9ucyIpO25leHR9CiAgCiAgI2FuZCBmaWx0ZXIgc3AgYmFzZWQgb24gdGhlIGxvY2FsaXRpZXMgdGhhdCBoYXZlIEZzdCB2YWx1ZXMKICBzcDwtc3Bbc3Akc2FtcGxlICVpbiUgcm93bmFtZXMoZ3NsRlNUbSksXQogIAogICNhbmQgdmljZSB2ZXJzYQogIAogIGdzbEZTVG08LSBnc2xGU1RtW3doaWNoKHJvd25hbWVzKGdzbEZTVG0pICVpbiUgdW5pcXVlKHNwJHNhbXBsZSkpLHdoaWNoKHJvd25hbWVzKGdzbEZTVG0pICVpbiUgdW5pcXVlKHNwJHNhbXBsZSkpXQogIAoKCiAgI2NyZWF0ZSBhIGxvY2F0aW9ucyBkYXRhIGZyYW1lIHRoYXQgaGFzIGFsbCB0aGUgbG9jYWxpdGllcyBwbHVzIGxhdHMgYW5kIGxvbmdzIGFuZCB0aGVpciBWZXJvbiByZWdpb24uCiAgbG9jczwtYXMuZGF0YS5mcmFtZSh1bmlxdWUoc3Akc2FtcGxlKSkKICBuYW1lcyhsb2NzKTwtInNhbXBsZSIKICAjbG9jcyRMb25nPC1zcCRkZWNpbWFsTG9uZ2l0dWRlW3doaWNoKGxvY3MgJWluJSBzcCRzYW1wbGUpXQogICNjYW4ndCBkbyBhIHVuaXF1ZSBvbiBzYW1wbGUsIGxhdHMgYW5kIGxvbmdzIGJlY2F1c2Ugc29tZSBzYW1wbGVzIGhhdmUgbm9uLXVuaXF1ZSBsYXRzIGFuZCBsb25ncyEgU28gSSBkbyBhIGpvaW4gYW5kIHRha2UgdGhlIGZpcnN0IG1hdGNoLgogIGxvY3M8LWpvaW4obG9jcyxzcFtjKCJzYW1wbGUiLCJkZWNpbWFsTG9uZ2l0dWRlIiwiZGVjaW1hbExhdGl0dWRlIgogICAgICAgICAgICAgICAgICAgICAgICwiVmVyb25EaXZpcyIpXSwgYnk9InNhbXBsZSIsIG1hdGNoPSJmaXJzdCIpCiAgCiAgI3NvcnQgZ3NsRlNUbQogIGdzbEZTVG08LWdzbEZTVG1bb3JkZXIocm93bmFtZXMoZ3NsRlNUbSkpLG9yZGVyKGNvbG5hbWVzKGdzbEZTVG0pKV0KICAjIGNvbnZlcnQgdG8gZGF0YSBmcmFtZSB3aXRoIHBvcHNhbXBsZSBuYW1lcyBhcyBmaXJzdCBjb2x1bW4KICBnc2xGU1RtPC1jYmluZChzYW1wbGU9bG9jcyRzYW1wbGUsYXMuZGF0YS5mcmFtZShnc2xGU1RtKSkKICAKICAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiAgIyAzLiBDYWxjdWxhdGUgR3JlYXQgQ2lyY2xlIERpc3RhbmNlCiAgZ2NkaXN0X2ttIDwtIHBvaW50RGlzdGFuY2UobG9jc1ssMjozXSxsb25sYXQ9VCkvMTAwMAogICNzeW1tZXRyaWNpemUgdGhlIG1hdHJpeAogIGdjZGlzdF9rbVt1cHBlci50cmkoZ2NkaXN0X2ttKV08LXQoZ2NkaXN0X2ttKVt1cHBlci50cmkoZ2NkaXN0X2ttKV0KICAKICAjY2JpbmQgb24gdGhlIHNhbXBsZSBuYW1lcwogIGdjZGlzdF9rbSA8LSBjYmluZChzYW1wbGU9bG9jcyRzYW1wbGUsYXMuZGF0YS5mcmFtZShnY2Rpc3Rfa20pKQogIAogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiAgIzQuIEZ1bGwgTW9kZWwKICAKICBjYXQoIlJ1bm5pbmcgRnVsbCBNb2RlbCIpCiAgCiAgCiAgcmVnaW9uczwtY2JpbmQobG9jc1ssYygxLDIsMyldLFZlcm9uRGl2aXM9cmVwX2xlbigxLGxlbmd0aChsb2NzWywxXSkpKQogIGlmKGxlbmd0aCh1bmlxdWUobG9jcyRWZXJvbkRpdmlzKSkgPiAxKXsKICAgIHJlZ2lvbnM8LWNiaW5kKGxvY3NbLGMoMSwyLDMpXSx3aXRoKGxvY3MsIGRhdGEuZnJhbWUobW9kZWwubWF0cml4KH5WZXJvbkRpdmlzKzApKSkpCiAgfQogIAogIGdzbEZTVG1sbDwtY2JpbmQobG9jc1ssYygyLDMpXSxnc2xGU1RtKQogIAogIGdkbS5mb3JtYXQuZnVsbDwtZm9ybWF0c2l0ZXBhaXIoYmlvRGF0YT1nc2xGU1RtLCBiaW9Gb3JtYXQ9MywgcHJlZERhdGE9cmVnaW9ucyxYQ29sdW1uID0gImRlY2ltYWxMb25naXR1ZGUiLCBZQ29sdW1uID0gImRlY2ltYWxMYXRpdHVkZSIsIHNpdGVDb2x1bW49InNhbXBsZSIsIGRpc3RQcmVkcz1saXN0KGdjZGlzdF9rbSkpCiAgCiAgICAgI3phcCBwb3B1bGF0aW9uIHBhaXJzIHdpdGggMCBnZW9ncmFwaGljYWwgZGlzdGFuY2UgYmV0d2VlbiB0aGVtLiBUcm91YmxpbmcuCiAgICB6YXBzPC13aGljaChnZG0uZm9ybWF0LmZ1bGwkczIubWF0cml4XzE9PTApCiAgICAKICAgIGlmKGxlbmd0aCh6YXBzKT4wKSB7CiAgICBnZG0uZm9ybWF0LmZ1bGw8LWdkbS5mb3JtYXQuZnVsbFstemFwcyxdCiAgICB9CiAgCiAgIyBydW4gdGhlIGZ1bGwgbW9kZWwsIGFuZCB0aGUgbW9kZWwgd2l0aCBvbmx5IGRpc3RhbmNlCiAgZnVsbGdkbTwtZ2RtKGdkbS5mb3JtYXQuZnVsbCkKICBkaXN0Z2RtPC1nZG0oZ2RtLmZvcm1hdC5mdWxsWyxjKDE6NixncmVwKCJtYXRyaXhfMSIsbmFtZXMoZ2RtLmZvcm1hdC5mdWxsKSkpXSkKICAKICBpZihpcy5udWxsKGZ1bGxnZG0pIHwgaXMubnVsbChkaXN0Z2RtKSl7CiAgICAgICAgY2F0KCJObyBzb2x1dGlvbiBvYnRhaW5lZCBvbiBGdWxsIE1vZGVsIikKICAgICAgICBub3NvbHV0aW9uLmZ1bGxbW2dzbF1dPC1nZG0uZm9ybWF0LmZ1bGwKICAgICAgICBuZXh0fQogIAogICMgcHVsbCBvdXQgc3RhdHMKICAgI2RpZmZlcmVuY2UgaW4gZGV2aWFuY2UKICAgIGRlbHRhZGV2LnJlZ2lvbnM8LWRpc3RnZG0kZ2RtZGV2aWFuY2UtZnVsbGdkbSRnZG1kZXZpYW5jZQogICAgCiAgICAjcGVyY2VudCBvZiBudWxsIGRldmlhbmNlIGV4cGxhaW5lZCBieSB0aGUgbW9kZWwgd2l0aCBqdXN0IGRpc3RhbmNlCiAgICBleHBsYWluZWRkZXYuZGlzdDwtZGlzdGdkbSRleHBsYWluZWQKICAgIAogICAgZ2RtLnJlZ2lvbnMuZGV2aWFuY2U8LWZ1bGxnZG0kZ2RtZGV2aWFuY2UKICAgIGdkbS5yZWdpb25zLmV4cGxhaW5lZDwtZnVsbGdkbSRleHBsYWluZWQKCiAgICBnZG0ubm8ucmVnaW9ucy5kZXZpYW5jZTwtZGlzdGdkbSRnZG1kZXZpYW5jZQogICAgZ2RtLm5vLnJlZ2lvbnMuZXhwbGFpbmVkPC1kaXN0Z2RtJGV4cGxhaW5lZAogIAogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwogICAgIyA0QS4gUGVyZm9ybSBNb250ZS1DYXJsbyBwZXJtdXRhdGlvbnMgdG8gZGV2ZWxvcCBhIG51bGwgZGlzdHJpYnV0aW9uIAogICAgIyAgICBvZiBkZXZpYW5jZSB2YWx1ZXMgYW5kIGRldGVybWluZSBzaWduaWZpY2FuY2UgKHB2YWx1ZSkKICAgIGdkbS5mb3JtYXQucmFuZC5mdWxsPC1nZG0uZm9ybWF0LmZ1bGwKICAgIHJhbmQuZGVsdGFzLmZ1bGw8LXZlY3RvcigpIAogICAgcmFuZC5leHBsYWluZWQuZnVsbDwtdmVjdG9yKCkKICAKICAgIHdoaWxlKGxlbmd0aChyYW5kLmRlbHRhcy5mdWxsKSA8IDEwMDApIHsKICAgICAgZ2RtLmZvcm1hdC5yYW5kLmZ1bGwkZGlzdGFuY2U8LXNhbXBsZShnZG0uZm9ybWF0LnJhbmQuZnVsbCRkaXN0YW5jZSxzaXplPWxlbmd0aChnZG0uZm9ybWF0LnJhbmQuZnVsbCRkaXN0YW5jZSkpCiAgICAgIGdkbS5iYXJyaWVyLnJhbmQuZnVsbDwtZ2RtKGdkbS5mb3JtYXQucmFuZC5mdWxsKQogICAgICBnZG0ubm8uYmFycmllci5yYW5kLmZ1bGw8LWdkbShnZG0uZm9ybWF0LnJhbmQuZnVsbFssYygxOjYsZ3JlcCgibWF0cml4XzEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXMoZ2RtLmZvcm1hdC5yYW5kLmZ1bGwpKSldKQogICAgCiAgICAgICAgIyBpZiBubyBzb2x1dGlvbiBvYnRhaW5lZCwgZ28gdG8gbmV4dCBnc2wKICAgICAgaWYoaXMubnVsbChnZG0uYmFycmllci5yYW5kLmZ1bGwpIHwgaXMubnVsbChnZG0ubm8uYmFycmllci5yYW5kLmZ1bGwpKXtuZXh0fQogICAgICAKICAgICAgZGVsdGFkZXYucmFuZC5mdWxsPC1nZG0ubm8uYmFycmllci5yYW5kLmZ1bGwkZ2RtZGV2aWFuY2UtZ2RtLmJhcnJpZXIucmFuZC5mdWxsJGdkbWRldmlhbmNlCiAgICAgIGV4cGxhaW5lZC5yYW5kLmZ1bGw8LWdkbS5uby5iYXJyaWVyLnJhbmQuZnVsbCRleHBsYWluZWQKICAgICAgCiAgICAgIHJhbmQuZGVsdGFzLmZ1bGw8LWMocmFuZC5kZWx0YXMuZnVsbCxkZWx0YWRldi5yYW5kLmZ1bGwpCiAgICAgIHJhbmQuZXhwbGFpbmVkLmZ1bGw8LWMocmFuZC5leHBsYWluZWQuZnVsbCxleHBsYWluZWQucmFuZC5mdWxsKQogICAgfQogICAgcHZhbHVlX3JlZ2lvbnMuZnVsbDwtbGVuZ3RoKHdoaWNoKGFicyhkZWx0YWRldi5yZWdpb25zKSA8IGFicyhyYW5kLmRlbHRhcy5mdWxsKSkpL2xlbmd0aChyYW5kLmRlbHRhcy5mdWxsKQogICAgcHZhbHVlX2Rpc3QuZnVsbDwtbGVuZ3RoKHdoaWNoKGFicyhleHBsYWluZWRkZXYuZGlzdCkgPCBhYnMocmFuZC5leHBsYWluZWQuZnVsbCkpKS9sZW5ndGgocmFuZC5leHBsYWluZWQuZnVsbCkKICAgIAogICAgc3RhdHMuMTwtYyhnc2wsZ2RtLnJlZ2lvbnMuZGV2aWFuY2UsZ2RtLnJlZ2lvbnMuZXhwbGFpbmVkLGdkbS5uby5yZWdpb25zLmRldmlhbmNlLGdkbS5uby5yZWdpb25zLmV4cGxhaW5lZCxkZWx0YWRldi5yZWdpb25zLHB2YWx1ZV9yZWdpb25zLmZ1bGwscHZhbHVlX2Rpc3QuZnVsbCkKICAgIAogICAgc3RhdHMuZnVsbFtucm93KHN0YXRzLmZ1bGwpKzEsXTwtc3RhdHMuMQogICAgCiAgICBnZG0uZnVsbFtbZ3NsXV08LWZ1bGxnZG0KICAgIAogICAgCn0KICAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBDYWxjdWxhdGUgT3ZlcndhdGVyIERpc3RhbmNlcyMKICAjU2F2ZSBmb3IgbGF0ZXIjIwogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiAgIyA1LiBDcmVhdGUgYSBzdWJzZXQgb2YgdGhlIGRpc3RhbmNlIG1hdHJpY2VzIGluY2x1ZGluZyBvbmx5IHRoZSBsb2NhbGl0aWVzIGZyb20KICAjICAgIHR3byBuZWlnaGJvcmluZyBWZXJvbiByZWdpb25zLgogIAogICNtYWtlIGEgdGFibGUgdG8ga2VlcCB0cmFjayBvZiBhbGwgdGhlc2UgdGVzdHMgZm9yIGVhY2ggc3BlY2llcwogIAogIGZvcihqIGluIDE6MTYpewogICAgazwtaysxCiAgICBiYXJyaWVyPC1jKGJhcnJpZXJzW2osMV0sYmFycmllcnNbaiwyXSkKICAgIHN1YnNldF9sb2NzPC13aGljaChsb2NzJFZlcm9uRGl2aXM9PWJhcnJpZXJbMV0gfCBsb2NzJFZlcm9uRGl2aXM9PWJhcnJpZXJbMl0pCiAgICBsb2NzMjwtbG9jc1tzdWJzZXRfbG9jcyxdCiAgICAKICAgIAogICAgTnVtcG9wczE8LWxlbmd0aChsb2NzMiRzYW1wbGVbd2hpY2gobG9jcyRWZXJvbkRpdmlzPT1iYXJyaWVyWzFdKV0pCiAgICBOdW1wb3BzMjwtbGVuZ3RoKGxvY3MyJHNhbXBsZVt3aGljaChsb2NzJFZlcm9uRGl2aXM9PWJhcnJpZXJbMl0pXSkKICAgIAogICAgY2F0KCJOb3cgU3RhcnRpbmciLGJhcnJpZXIsIlxuIikKICAgIAogICAgZ2NkaXN0X2ttMjwtZ2NkaXN0X2ttW3N1YnNldF9sb2NzLGMoMSxzdWJzZXRfbG9jcysxKV0KICAgIGdzbEZTVG0yPC1nc2xGU1RtW3N1YnNldF9sb2NzLGMoMSxzdWJzZXRfbG9jcysxKV0KICAgIAogICAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKICAgICMgNi4gQ3JlYXRlIGEgZHVtbXkgZGlzdGFuY2UgbWF0cml4IGZvciBlYWNoIHB1dGF0aXZlICJiYXJyaWVyIiAKICAgICMgICAgIGJldHdlZW4gdGhlIHR3byByZWdpb25zICgxcyBhbmQgMHMpCiAgICAKICAgIGJhcnJpZXJfbTI8LWFzLm1hdHJpeChkaXN0KGFzLm51bWVyaWMobG9jczIkVmVyb25EaXZpcyAlaW4lIGJhcnJpZXJbMV0pKSkKICAgIAogICAgYmFycmllcl9tMiA8LSBjYmluZChzYW1wbGU9bG9jczIkc2FtcGxlLGFzLmRhdGEuZnJhbWUoYmFycmllcl9tMikpCiAgICAKICAgICNpZiB0aGVyZSBhcmVuJ3QgZW5vdWdoIHNhbXBsZXMgb24gZWl0aGVyIHNpZGUgb2YgdGhpcyBiYXJyaWVyLCB0aGVuIHJlY29yZCB0aGlzIGFzIG5vbiB0ZXN0YWJsZSBhbmQgZ28gdG8gbmV4dCBiYXJyaWVyCiAgICBpZihOdW1wb3BzMStOdW1wb3BzMiA8IDMpe2NhdCgiTGVzcyB0aGFuIHRocmVlIHNhbXBsZWQgcG9wdWxhdGlvbnM7IG5vdCB0ZXN0YWJsZVxuIik7IGJhcnJpZXJ0ZXN0c1trLF08LWMoZ3NsLGJhcnJpZXJbMV0sTnVtcG9wczEsYmFycmllclsyXSxOdW1wb3BzMixGLEYpO25leHR9CiAgICBpZiggTnVtcG9wczEgPCAxKSB7Y2F0KCJub3QgZW5vdWdoIHBvcHVsYXRpb25zIHdpdGhpbiIsYmFycmllclsxXSwiXG4iKSA7IGJhcnJpZXJ0ZXN0c1trLF08LWMoZ3NsLGJhcnJpZXJbMV0sTnVtcG9wczEsYmFycmllclsyXSxOdW1wb3BzMixGLEYpO25leHR9CiAgICBpZiggTnVtcG9wczIgPCAxKSB7Y2F0KCJub3QgZW5vdWdoIHBvcHVsYXRpb25zIHdpdGhpbiIsYmFycmllclsyXSwiXG4iKSA7IGJhcnJpZXJ0ZXN0c1trLF08LWMoZ3NsLGJhcnJpZXJbMV0sTnVtcG9wczEsYmFycmllclsyXSxOdW1wb3BzMixGLEYpO25leHR9CiAgICAKICAgICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKICAgICMgNy4gUnVuIHRocm91Z2ggZ2RtIHdpdGggdGhlIGJhcnJpZXIgYW5kIHdpdGhvdXQuIFNhdmUgdGhlIGRldmlhbmNlIHZhbHVlcy4KICAgIAogICAgbG9jczIkc2FtcGxlPC1hcy5jaGFyYWN0ZXIobG9jczIkc2FtcGxlKQogICAgZ3NsRlNUbTIkc2FtcGxlPC1hcy5jaGFyYWN0ZXIoZ3NsRlNUbTIkc2FtcGxlKQogICAgZ2NkaXN0X2ttMiRzYW1wbGU8LWFzLmNoYXJhY3RlcihnY2Rpc3Rfa20yJHNhbXBsZSkKICAgIAogICAgZ2RtLmZvcm1hdDwtZm9ybWF0c2l0ZXBhaXIoYmlvRGF0YT1nc2xGU1RtMiwgYmlvRm9ybWF0PTMsIHByZWREYXRhPWxvY3MyWywxOjNdLFhDb2x1bW4gPSAiZGVjaW1hbExvbmdpdHVkZSIsIFlDb2x1bW4gPSAiZGVjaW1hbExhdGl0dWRlIiwgc2l0ZUNvbHVtbj0ic2FtcGxlIiwgZGlzdFByZWRzPWxpc3QoZ2NkaXN0X2ttMixiYXJyaWVyX20yKSkKICAgIAogICAgICN6YXAgcG9wdWxhdGlvbiBwYWlycyB3aXRoIDAgZ2VvZ3JhcGhpY2FsIGRpc3RhbmNlIGJldHdlZW4gdGhlbS4gVHJvdWJsaW5nLgogICAgemFwczwtd2hpY2goZ2RtLmZvcm1hdCRzMi5tYXRyaXhfMT09MCkKICAgIAogICAgaWYobGVuZ3RoKHphcHMpPjApIHsKICAgIGdkbS5mb3JtYXQ8LWdkbS5mb3JtYXRbLXphcHMsXQogICAgfQogICAgCiAgICAjcnVuIGdkbSB3aXRoIGFuZCB3aXRob3V0IHRoZSBiYXJyaWVyCiAgICBnZG0uYmFycmllcjwtZ2RtKGdkbS5mb3JtYXQpCiAgICBnZG0ubm8uYmFycmllcjwtZ2RtKGdkbS5mb3JtYXRbLC1ncmVwKCJtYXRyaXhfMiIsbmFtZXMoZ2RtLmZvcm1hdCkpXSkKICAgIAogICAgIyBydW4gbXJkbQogICAgbXJkbTwtTVJNKGZvcm11bGEgPSBkaXN0YW5jZSB+IHMyLm1hdHJpeF8xICsgczIubWF0cml4XzIsIGRhdGE9Z2RtLmZvcm1hdCxucGVybSA9IDEwMDAwKQogICAgCiAgICAjVFJPVUJMRVNIT09USU5HOiBzYXZlIGZzdCBtYXRyaWNlcyBmcm9tIGdkbSBtb2RlbHMgdGhhdCBvYnRhaW4gbm8gc29sdXRpb24KICAgIGlmKGlzLm51bGwoZ2RtLmJhcnJpZXIpIHwgaXMubnVsbChnZG0ubm8uYmFycmllcikpCiAgICAgIHtjYXQoIk5vIFNvbHV0aW9uIE9idGFpbmVkIFxuIik7CiAgICAgIG5vc29sdXRpb25bW3Bhc3RlKGdzbCxiYXJyaWVyWzFdLE51bXBvcHMxLGJhcnJpZXJbMl0sTnVtcG9wczIsc2VwPSIsIildXTwtbGlzdChsb2NzMixnY2Rpc3Rfa20yLGdzbEZTVG0yLGdkbS5mb3JtYXQpOwogICAgICBiYXJyaWVydGVzdHNbayxdPC1jKGdzbCxiYXJyaWVyWzFdLE51bXBvcHMxLGJhcnJpZXJbMl0sTnVtcG9wczIsVCxGKTsKICAgICAgbmV4dH0KICAgIAogICAgI2RpZmZlcmVuY2UgaW4gZGV2aWFuY2UKICAgIGRlbHRhZGV2PC1nZG0ubm8uYmFycmllciRnZG1kZXZpYW5jZS1nZG0uYmFycmllciRnZG1kZXZpYW5jZQogICAgCiAgICAjcGVyY2VudCBvZiBudWxsIGRldmlhbmNlIGV4cGxhaW5lZCBieSB0aGUgbW9kZWwgd2l0aCBqdXN0IGRpc3RhbmNlCiAgICBleHBsYWluZWRkZXY8LWdkbS5uby5iYXJyaWVyJGV4cGxhaW5lZAogICAgCiAgICAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKICAgICMgOC4gUGVyZm9ybSBNb250ZS1DYXJsbyBwZXJtdXRhdGlvbnMgdG8gZGV2ZWxvcCBhIG51bGwgZGlzdHJpYnV0aW9uIAogICAgIyAgICBvZiBkZXZpYW5jZSB2YWx1ZXMgYW5kIGRldGVybWluZSBzaWduaWZpY2FuY2UgKHB2YWx1ZSkKICAgIGdkbS5mb3JtYXQucmFuZDwtZ2RtLmZvcm1hdAogICAgcmFuZC5kZWx0YXM8LXZlY3RvcigpIAogICAgcmFuZC5leHBsYWluZWQ8LXZlY3RvcigpCiAgICAKICAgIHdoaWxlKGxlbmd0aChyYW5kLmRlbHRhcykgPCAxMDAwKSB7CiAgICAgIGdkbS5mb3JtYXQucmFuZCRkaXN0YW5jZTwtc2FtcGxlKGdkbS5mb3JtYXQucmFuZCRkaXN0YW5jZSxzaXplPWxlbmd0aChnZG0uZm9ybWF0LnJhbmQkZGlzdGFuY2UpKQogICAgICBnZG0uYmFycmllci5yYW5kPC1nZG0oZ2RtLmZvcm1hdC5yYW5kKQogICAgICBnZG0ubm8uYmFycmllci5yYW5kPC1nZG0oZ2RtLmZvcm1hdC5yYW5kWywtZ3JlcCgibWF0cml4XzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lcyhnZG0uZm9ybWF0KSldKQogICAgICBpZihpcy5udWxsKGdkbS5iYXJyaWVyLnJhbmQpIHwgaXMubnVsbChnZG0ubm8uYmFycmllci5yYW5kKSl7bmV4dH0KICAgICAgZGVsdGFkZXYucmFuZDwtZ2RtLm5vLmJhcnJpZXIucmFuZCRnZG1kZXZpYW5jZS1nZG0uYmFycmllci5yYW5kJGdkbWRldmlhbmNlCiAgICAgIGV4cGxhaW5lZC5yYW5kPC1nZG0ubm8uYmFycmllci5yYW5kJGV4cGxhaW5lZAogICAgICAKICAgICAgcmFuZC5kZWx0YXM8LWMocmFuZC5kZWx0YXMsZGVsdGFkZXYucmFuZCkKICAgICAgcmFuZC5leHBsYWluZWQ8LWMocmFuZC5leHBsYWluZWQsZXhwbGFpbmVkLnJhbmQpCiAgICB9CiAgICBwdmFsdWVfYmFycmllcjwtbGVuZ3RoKHdoaWNoKGFicyhkZWx0YWRldikgPCBhYnMocmFuZC5kZWx0YXMpKSkvbGVuZ3RoKHJhbmQuZGVsdGFzKQogICAgcHZhbHVlX2Rpc3Q8LWxlbmd0aCh3aGljaChhYnMoZXhwbGFpbmVkZGV2KSA8IGFicyhyYW5kLmV4cGxhaW5lZCkpKS9sZW5ndGgocmFuZC5leHBsYWluZWQpCiAgICAKICAgIGNhdCgiR29vZCBTb2x1dGlvbiBcbiIpCiAgICAKICAgIAogICAgI3NhdmUgc3RhdHMKICAgIGdkbS5iYXJyaWVyLmRldmlhbmNlPC1nZG0uYmFycmllciRnZG1kZXZpYW5jZQogICAgZ2RtLmJhcnJpZXIuZXhwbGFpbmVkPC1nZG0uYmFycmllciRleHBsYWluZWQKCiAgICBnZG0ubm8uYmFycmllci5kZXZpYW5jZTwtZ2RtLm5vLmJhcnJpZXIkZ2RtZGV2aWFuY2UKICAgIGdkbS5uby5iYXJyaWVyLmV4cGxhaW5lZDwtZ2RtLm5vLmJhcnJpZXIkZXhwbGFpbmVkCgogICAgaW1wdC5kaXN0LmdkbS5iYXJyaWVyPC1zdW0oZ2RtLmJhcnJpZXIkY29lZmZpY2llbnRzWzE6Z2RtLmJhcnJpZXIkc3BsaW5lc1sxXV0pCiAgICBpbXB0LmJhcnJpZXIuZ2RtLmJhcnJpZXI8LXN1bShnZG0uYmFycmllciRjb2VmZmljaWVudHNbZ2RtLmJhcnJpZXIkc3BsaW5lc1sxXSsxOmdkbS5iYXJyaWVyJHNwbGluZXNbMV1dKQogICAgaW1wdC5kaXN0LmdkbS5uby5iYXJyaWVyPC1zdW0oZ2RtLm5vLmJhcnJpZXIkY29lZmZpY2llbnRzWzE6Z2RtLm5vLmJhcnJpZXIkc3BsaW5lc1sxXV0pCiAgICAKICAgIG1yZG0ucnNxdWFyZWQ8LW1yZG0kci5zcXVhcmVkWzFdCiAgICBtcmRtLnJzcXVhcmVkLnB2YWx1ZTwtbXJkbSRyLnNxdWFyZWRbMl0KICAgIG1yZG0uZGlzdC5wdmFsdWU8LW1yZG0kY29lZlsyLDJdCiAgICBtcmRtLmJhcnJpZXIucHZhbHVlPC1tcmRtJGNvZWZbMywyXQogICAgCiAgICAKICAgCiAgICBzdGF0c19tb2RlbDwtYyhnc2wscGFzdGUoYmFycmllclsxXSxiYXJyaWVyWzJdLHNlcD0iLSIpLGdkbS5iYXJyaWVyLmRldmlhbmNlLGdkbS5iYXJyaWVyLmV4cGxhaW5lZCwgaW1wdC5kaXN0LmdkbS5iYXJyaWVyLCBpbXB0LmJhcnJpZXIuZ2RtLmJhcnJpZXIsIGdkbS5uby5iYXJyaWVyLmRldmlhbmNlLCBnZG0ubm8uYmFycmllci5leHBsYWluZWQsaW1wdC5kaXN0LmdkbS5uby5iYXJyaWVyLCBkZWx0YWRldixwdmFsdWVfYmFycmllcixwdmFsdWVfZGlzdCxtcmRtLnJzcXVhcmVkLG1yZG0ucnNxdWFyZWQucHZhbHVlLG1yZG0uZGlzdC5wdmFsdWUsbXJkbS5iYXJyaWVyLnB2YWx1ZSkKICAgIAogICAgc3RhdHNbbnJvdyhzdGF0cykrMSxdPC1zdGF0c19tb2RlbAogICAgCiAgICAjcmVjb3JkIHRoaXMgaW4gdGhlIHRhYmxlCiAgICBiYXJyaWVydGVzdHNbayxdPC1jKGdzbCxiYXJyaWVyWzFdLE51bXBvcHMxLGJhcnJpZXJbMl0sTnVtcG9wczIsVCxUKQogICAgCiAgfQogIAoKCgoKc3RhdHMuZnVsbCRHRE0ucmVnaW9ucy5xdmFsdWU8LXAuYWRqdXN0KGFzLm51bWVyaWMoc3RhdHMuZnVsbCRQdmFsdWVfcmVnaW9ucyksbWV0aG9kPSJmZHIiKQpzdGF0cy5mdWxsJEdETS5kaXN0YW5jZS5xdmFsdWU8LXAuYWRqdXN0KGFzLm51bWVyaWMoc3RhdHMuZnVsbCRQdmFsdWVfZGlzdCksbWV0aG9kPSJmZHIiKQoKc3RhdHMkR0RNLnF2YWx1ZTwtcC5hZGp1c3QoYXMubnVtZXJpYyhzdGF0cyRQdmFsdWVfYmFycmllciksbWV0aG9kPSJmZHIiKQpzdGF0cyRNUkRNLnIyLnF2YWx1ZTwtcC5hZGp1c3QoYXMubnVtZXJpYyhzdGF0cyRNUkRNLnJzcXVhcmVkLnB2YWx1ZSksbWV0aG9kPSJmZHIiKQpzdGF0cyRNUkRNLmRpc3QucXZhbHVlPC1wLmFkanVzdChhcy5udW1lcmljKHN0YXRzJE1SRE0uZGlzdC5wdmFsdWUpLG1ldGhvZD0iZmRyIikKc3RhdHMkTVJETS5iYXJyaWVyLnF2YWx1ZTwtcC5hZGp1c3QoYXMubnVtZXJpYyhzdGF0cyRNUkRNLmJhcnJpZXIucHZhbHVlKSxtZXRob2Q9ImZkciIpCgoKCiMgZG8gc29tZSBmaWd1cmluZyB3aXRoIHRoZSByZXN1bHRzCmxlbmd0aChiYXJyaWVydGVzdHNbd2hpY2goYmFycmllcnRlc3RzJFRlc3Q9PVQpLDFdKQojd29ya2luZyBHRE0gdGVzdHMKbGVuZ3RoKGJhcnJpZXJ0ZXN0c1t3aGljaChiYXJyaWVydGVzdHMkU29sdXRpb249PVQgJiBiYXJyaWVydGVzdHMkVGVzdD09VCksMV0pCiNmYWlsZWQgR0RNIHRlc3RzCmxlbmd0aChiYXJyaWVydGVzdHNbd2hpY2goYmFycmllcnRlc3RzJFNvbHV0aW9uPT1GICYgYmFycmllcnRlc3RzJFRlc3Q9PVQpLDFdKQoKCgpsZW5ndGgoc3RhdHNbd2hpY2goc3RhdHMkR0RNLnF2YWx1ZSA8PSAwLjAyKSwxXSkKCmxlbmd0aChzdGF0c1t3aGljaChzdGF0cyRNUkRNLmJhcnJpZXIucXZhbHVlIDw9IDAuMDIpLDFdKQoKI292ZXJsYXAgYmV0d2VlbiBNUkRNIGFuZCBHRE0KbGVuZ3RoKHN0YXRzW3doaWNoKHN0YXRzJEdETS5xdmFsdWUgPD0gMC4wMiAmIHN0YXRzJE1SRE0uYmFycmllci5xdmFsdWUgPD0gMC4wMiksMV0pCgoKCgoKZ29vZGJhcnJpZXJzPC1zdGF0cyAlPiUgZmlsdGVyKEdETS5xdmFsdWUgPCAwLjAyKSAlPiUgZ3JvdXBfYnkoQmFycmllcikgJT4lIHN1bW1hcml6ZShnb29kYmFycmllcnMgPSBuKCkpCgphbGxiYXJyaWVyczwtc3RhdHMgJT4lIGdyb3VwX2J5KEJhcnJpZXIpICU+JSBzdW1tYXJpemUoYmFycmllcl90ZXN0cyA9IG4oKSkKCmJhcnJpZXJfcmF0aW9zPC1sZWZ0X2pvaW4oYWxsYmFycmllcnMsZ29vZGJhcnJpZXJzLGJ5PSJCYXJyaWVyIikKCmJhcnJpZXJfcmF0aW9zJGdvb2RiYXJyaWVyc1t3aGljaChpcy5uYShiYXJyaWVyX3JhdGlvcyRnb29kYmFycmllcnMpKV08LTAKCmJhcnJpZXJfcmF0aW9zPC1tdXRhdGUoYmFycmllcl9yYXRpb3MsIGdvb2RiYXJyaWVycy9iYXJyaWVyX3Rlc3RzKQoKCmthYmxlKGJhcnJpZXJfcmF0aW9zKQoKd3JpdGUuY3N2KHN0YXRzLCIuL291dHB1dC9HRE1fb3V0cHV0X1dDVGhldGFfMTAwMHJlcHMuY3N2IikKd3JpdGUuY3N2KGJhcnJpZXJfcmF0aW9zLCAiLi9vdXRwdXQvR0RNX0pvc3REX1dDVGhldGFfYmFycmllcnMuY3N2IikKYGBgCgojIENyZWF0ZSBhIGhlYXRtYXAgZnJvbSBHRE0gcmVnaW9ucwpgYGB7ciBHRE0gSGVhdG1hcH0KCiNleHRyYWN0IHRoZSBpc3BsaW5lcwppc3BsaW5lczwtbGFwcGx5KGdkbS5mdWxsLGlzcGxpbmVFeHRyYWN0KQoKI2NyZWF0ZSBhIGZ1bmN0aW9uIHRoYXQgdGFrZXMgdGhlIGxhc3Qgcm93IG9mIGVhY2ggaXNwbGluZSA9IGltcG9ydGFuY2UsIGFuZCBsYXBwbHkgaXQKZ2RtLmltcG9ydGFuY2U8LWZ1bmN0aW9uKHApewogIHAkeVsyMDAsXQp9CmltcG9ydGFuY2U8LWxhcHBseShpc3BsaW5lcyxnZG0uaW1wb3J0YW5jZSkKCiMgY3JlYXRlIGEgZnVuY3Rpb24gdGhhdCB0cmFuc3Bvc2VzIGFuZCBjb252ZXJ0cyB0byBhIGRhdGEgZnJhbWUsIGFuZCBsYXBwbHkgaXQKZGF0YWZyYW1lcjwtZnVuY3Rpb24ocCl7CiAgcTwtYXMuZGF0YS5mcmFtZSh0KHApKQp9CgppbXBvcnRhbmNlMjwtbGFwcGx5KGltcG9ydGFuY2UsZGF0YWZyYW1lcikKCmltcG9ydGFuY2VfZGY8LVJlZHVjZShmdW5jdGlvbih0MSx0MikgbWVyZ2UodDEsdDIsYWxsPVQsc29ydD1GKSwgaW1wb3J0YW5jZTIpCgojaW1wb3J0YW5jZV9kZjwtaW1wb3J0YW5jZV9kZltvcmRlcihzdGF0cy5mdWxsJEdETS5yZWdpb25zLnF2YWx1ZSksXQojc3RhdHMuZnVsbDwtc3RhdHMuZnVsbFtvcmRlcihzdGF0cy5mdWxsJEdETS5yZWdpb25zLnF2YWx1ZSksXQoKIyBjb252ZXJ0IHRvIG1hdHJpeAppbXBvcnRhbmNlX21hdHJpeDwtYXMubWF0cml4KGltcG9ydGFuY2VfZGYpCiMgc3BsaXQgaW50byByZWdpb25zIGNvbXBvbmVudApyZWdpb25zX21hdHJpeDwtaW1wb3J0YW5jZV9tYXRyaXhbLDI6MTddCiMgYW5kIGRpc3RhbmNlIGNvbXBvbmVudApkaXN0YW5jZV9tYXRyaXg8LWltcG9ydGFuY2VfbWF0cml4WywxXQoKIyBzZXQgaW1wb3J0YW5jZSB2YWx1ZXMgZm9yIG1vZGVscyB0aGF0IHdpdGggbm9uLXNpZ25pZmljYW50IHJlZ2lvbnMgY29tcG9uZW50IGF0IHE8MC4wMSB0byB6ZXJvCnJlZ2lvbnNfbWF0cml4W3doaWNoKHN0YXRzLmZ1bGwkR0RNLnJlZ2lvbnMucXZhbHVlID4gMC4wMSksXVshaXMubmEocmVnaW9uc19tYXRyaXhbd2hpY2goc3RhdHMuZnVsbCRHRE0ucmVnaW9ucy5xdmFsdWUgPiAwLjAxKSxdKV08LTAKCiMgc2V0IGltcG9ydGFuY2UgdmFsdWVzIGZvciBtb2RlbHMgd2l0aCBub24tc2lnbmlmaWNhbnQgZGlzdGFuY2UgY29tcG9uZW50IGF0IHE8MC4wMSB0byB6ZXJvCmRpc3RhbmNlX21hdHJpeFt3aGljaChzdGF0cy5mdWxsJEdETS5kaXN0YW5jZS5xdmFsdWUgPiAwLjAxKV08LTAKCiMgc3RpY2sgdGhlIG1hdHJpeCBiYWNrIHRvZ2V0aGVyIGFuZCB0aGVuIHNjYWxlIGltcG9ydGFuY2UgdG8gcmVsYXRpdmUgdmFsdWVzIGJhc2VkIG9uIG1heCBpbXBvcnRhbmNlCgppbXBvcnRhbmNlX21hdHJpeDI8LWNiaW5kKGRpc3RhbmNlX21hdHJpeCxyZWdpb25zX21hdHJpeCkKCmltcG9ydGFuY2VfbWF0cml4MzwtaW1wb3J0YW5jZV9tYXRyaXgyL21heChpbXBvcnRhbmNlX21hdHJpeDIsbmEucm0gPSBUKQoKaW1wb3J0YW5jZV9kZjI8LWFzLmRhdGEuZnJhbWUoaW1wb3J0YW5jZV9tYXRyaXgzLHJvdy5uYW1lcyA9IHN0YXRzLmZ1bGwkU3BlY2llc19Mb2N1cykKCmltcG9ydGFuY2VfZGYyJFNwZWNpZXM8LW5hbWVzKGdkbS5mdWxsKQoKCiNkZWxldGUgdGhlIHNwZWNpZXMgdGhhdCBvbmx5IG9jY3VycmVkIGluIG9uZSByZWdpb24sIHRoZW4gZGVsZXRlIHRoYXQgY29sdW1uCmltcG9ydGFuY2VfZGYyPC1pbXBvcnRhbmNlX2RmMlt3aGljaChpcy5uYShpbXBvcnRhbmNlX2RmMiRWZXJvbkRpdmlzKSksXQppbXBvcnRhbmNlX2RmMjwtaW1wb3J0YW5jZV9kZjJbLC13aGljaChuYW1lcyhpbXBvcnRhbmNlX2RmMik9PSJWZXJvbkRpdmlzIildCgoKCgoKIyMgTWFrZSBhIGhlYXRtYXAgb2YgdGhlIGltcG9ydGFuY2UgdmFsdWVzCgojbWVsdCBmb3IgZ2dwbG90MgppbXBvcnRhbmNlX21lbHRlZDwtbWVsdChpbXBvcnRhbmNlX2RmMixpZC52YXJzID0gIlNwZWNpZXMiKQpjb2xuYW1lcyhpbXBvcnRhbmNlX21lbHRlZCk8LWMoIlNwZWNpZXMiLCJWYXJpYWJsZSIsIkltcG9ydGFuY2UiKQppbXBvcnRhbmNlX21lbHRlZCRTcGVjaWVzPC1hcy5mYWN0b3IoaW1wb3J0YW5jZV9tZWx0ZWQkU3BlY2llcykKCiNiYXNlcGxvdAppcDwtZ2dwbG90KGltcG9ydGFuY2VfbWVsdGVkLGFlcyh5PVNwZWNpZXMseD1WYXJpYWJsZSxmaWxsPUltcG9ydGFuY2UpKQoKI2FkZCBnZW9tX3RpbGUsIHR1cm4gdGhlIHgtYXhpcyBlbGVtZW50cyBieSA5MCBkZWdyZWVzLCByZXZlcnNlIHRoZSBuYW1lcyBvbiB0aGUgeS1heGlzLCBhbmQgdXNlIGEgZGl2ZXJnaW5nIGNvbG9yIHNjaGVtZSB0byBoaWdobGlnaHQgaHlwb3RoZXNlcyB3aXRoID41MCUgcmVsIHByb2IuCmlwPC1pcCtnZW9tX3RpbGUoKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSsKICB5bGltKHJldihsZXZlbHMoaW1wb3J0YW5jZV9tZWx0ZWQkU3BlY2llcykpKSsKICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnM9Yygid2hpdGUiLCJwaW5rIiwicmVkIiksdmFsdWVzID0gYygwLDAuMDAwMDAxLDEpLAogICAgICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gImdyZXk1MCIsIGd1aWRlID0gImNvbG91cmJhciIpCmlwCgoKYGBgCgojIGRiUkRBCgpgYGB7ciBkYlJEQX0KCiMgcmVhZCBpbiB0aGUgRnN0L1BoaVN0IHRhYmxlIApsb2FkKCJ+L2dvb2dsZV9kcml2ZS9ESVBuZXRfR2FpdF9MaWdfQmlyZC9ESVBuZXRfV0c0X2ZpcnN0X3BhcGVycy9zdGF0aXN0aWNzL0J5X1NwZWNpZXMvUGFpcndpc2Vfc3RhdGlzdGljcy9zYW1wbGUvRElQbmV0X3N0cnVjdHVyZV9zYW1wbGVfV0NUaGV0YS5SZGF0YSIpCiNsb2FkKCJ+L0Rlc2t0b3AvRElQbmV0X3N0cnVjdHVyZV9zYW1wbGVfUGhpU1RfMDQyODE3LlJkYXRhIikKCgojIzEuIERhdGFmcmFtZSBmb3IgcmVzdWx0cwpzdGF0czwtZGF0YS5mcmFtZShTcGVjaWVzX0xvY3VzPWNoYXJhY3RlcigwKSxjb25zdHJhaW5lZC5pbmVydGlhPW51bWVyaWMoMCksdG90YWxJbmVydGlhPW51bWVyaWMoMCksUHJvcG9ydGlvbkNvbnN0cmFpbmVkPW51bWVyaWMoMCksYWRqLlIyLnRvdGFsPW51bWVyaWMoMCksbW9kZWxGPW51bWVyaWMoMCksbW9kZWxQdmFsdWU9bnVtZXJpYygwKSxwY3hfVmFyPW51bWVyaWMoMCkscGN4X3A9bnVtZXJpYygwKSxwY3lfVmFyPW51bWVyaWMoMCkscGN5X3A9bnVtZXJpYygwKSxiZXN0bW9kZWw9Y2hhcmFjdGVyKDApLCBjb25zdHJhaW5lZC5pbmVydGlhLmJlc3Q9bnVtZXJpYygwKSwgdG90YWwuaW5lcnRpYS5iZXN0PW51bWVyaWMoMCksIHByb3BvcnRpb24uY29uc3RyYWluZWQuaW5lcnRpYS5iZXN0PW51bWVyaWMoMCksIGFkai5SMi5iZXN0Lm1vZGVsPW51bWVyaWMoMCksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpzdGF0cyRTcGVjaWVzX0xvY3VzPC1hcy5jaGFyYWN0ZXIoc3RhdHMkU3BlY2llc19Mb2N1cykKI3N0YXRzJEJhcnJpZXI8LWFzLmNoYXJhY3RlcihzdGF0cyRCYXJyaWVyKQpzdGF0cyRiZXN0bW9kZWw8LWFzLmNoYXJhY3RlcihzdGF0cyRiZXN0bW9kZWwpCgojIE1ha2UgYW4gZW1wdHkgbGlzdCB0byBzYXZlIHJkYSBvdXRwdXQgZm9yIGVhY2ggc3BlY2llcwplc3VfbG9jaSA8LSB1bmlxdWUoaXBkYiRHZW51c19zcGVjaWVzX2xvY3VzKQphbGwuZ3NsLnJkYTwtc2FwcGx5KGVzdV9sb2NpLCBmdW5jdGlvbih4KSBOVUxMKQoKI21ha2UgZW1wdHkgZGF0YSBmcmFtZXMgdG8gc2F2ZSB2YXJpYW5jZSBhbmQgcHZhbHVlcwp0ZXJtLnZhcnM8LWRhdGEuZnJhbWUoZ3NsPWNoYXJhY3RlcigwKSkKdGVybS5wdmFsczwtZGF0YS5mcmFtZShnc2w9Y2hhcmFjdGVyKDApKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIDIuIFN1YnNhbXBsZSBmb3IgZWFjaCBzcGVjaWVzIG9mIGludGVyZXN0LCBhbmQgZmlsdGVyIGJhc2VkIG9uIFBoaV9TVCB0YWJsZS4KZm9yKGdzbCBpbiBlc3VfbG9jaSl7ICNnc2w8LSJMaW5ja2lhX2xhZXZpZ2F0YV9DTzEiICJUcmlkYWNuYV9jcm9jZWFfQ08xIiAiTHV0amFudXNfa2FzbWlyYV9DWUIiCiAgCiAgY2F0KCJcbiIsIlxuIiwiXG4iLCJOb3cgc3RhcnRpbmciLCBnc2wsICJcbiIpCiAgCiAgaWYoYW55KGlzLm5hKGRpZmZzdGF0c1tbZ3NsXV0pKSl7Y2F0KCJOQXMgaW4gRlNUIHRhYmxlLCBObyBkYlJEQSBjYWxjdWxhdGVkIik7IG5leHR9CiAgCiAgaWYoZGlmZnN0YXRzW1tnc2xdXT09IkZld2VyIHRoYW4gMyBzYW1wbGVkIHBvcHVsYXRpb25zIGFmdGVyIGZpbHRlcmluZy4gTm8gc3RhdHMgY2FsY3VsYXRlZCIpe2FsbC5nc2wucmRhW1tnc2xdXTwtIkZld2VyIHRoYW4gNSBzYW1wbGVkIHBvcHVsYXRpb25zIGFmdGVyIGZpbHRlcmluZy4iOyBjYXQoIkZld2VyIHRoYW4gNSBzYW1wbGVkIHBvcHVsYXRpb25zIGFmdGVyIGZpbHRlcmluZy4iKTtuZXh0fQogICBzcDwtaXBkYlt3aGljaChpcGRiJEdlbnVzX3NwZWNpZXNfbG9jdXM9PWdzbCksXQogIAogICNjbGVhbiB3ZWlyZCBiYWNrc2xhc2hlcyBmcm9tIG5hbWVzCiAgc3AkbG9jYWxpdHk8LWdzdWIoIlwiIiwiIixzcCRsb2NhbGl0eSkKICAKICBzcCRzYW1wbGU8LXBhc3RlKHNwJGxvY2FsaXR5LHJvdW5kKHNwJGRlY2ltYWxMYXRpdHVkZSwgZGlnaXRzPTApLHJvdW5kKHNwJGRlY2ltYWxMb25naXR1ZGUsIGRpZ2l0cz0wKSxzZXA9Il8iKSAgI3NldHMgdXAgYSB2YXJpYWJsZSB0aGF0IG1hdGNoZXMgdGhlIG5hbWUgaW4gRnN0IHRhYmxlCiAgc3A8LXNwW29yZGVyKHNwJHNhbXBsZSksXQogICMgTm90IGFsbCBsb2NhbGl0aWVzIGFyZSBpbmNsdWRlZCBpbiBWZXJvbidzIHJlZ2lvbmFsaXphdGlvbiAoZS5nLiBHdWFtKSwgc28gZ2V0IHRoZWlyIG5hbWVzIGFuZCB0aGVuIHphcCBOQXMKICBub25WZXJvbnBvcHM8LXVuaXF1ZShzcCRzYW1wbGVbaXMubmEoc3AkVmVyb25EaXZpcyldKQogIHNwPC1zcFshaXMubmEoc3AkVmVyb25EaXZpcyksXQogIAogICNzdWJzYW1wbGUgRnN0IAogIGdzbEZTVDwtZGlmZnN0YXRzW1tnc2xdXQogICNtYWtlIGEgbWF0cml4IG91dCBvZiBnc2xGU1QsIGNvbnZlcnQgbmVnYXRpdmUgdmFsdWVzIHRvIHplcm8KICBnc2xGU1RtPC1hcy5tYXRyaXgoZ3NsRlNUKQogIGdzbEZTVG1bd2hpY2goZ3NsRlNUbTwwKV08LTAuMAogIAogICN6YXAgd2VpcmQgc2xhc2hlcyBpbiB0aGUgbmFtZXMKICByb3duYW1lcyhnc2xGU1RtKTwtZ3N1YigiXCIiLCIiLHJvd25hbWVzKGdzbEZTVG0pKQogIGNvbG5hbWVzKGdzbEZTVG0pPC1yb3duYW1lcyhnc2xGU1RtKQogIAogICN6YXAgdGhlIHNhbWUgbmEgcG9wdWxhdGlvbnMgZnJvbSB0aGUgbGlzdCBvZiBub24gZXhpc3RlbnQgcG9wcyBmcm9tIFZlcm9uRGl2aXMKICBpZihhbnkocm93bmFtZXMoZ3NsRlNUbSkgJWluJSBub25WZXJvbnBvcHMpKXsKICAgIGdzbEZTVG08LWdzbEZTVG1bLSh3aGljaChyb3duYW1lcyhnc2xGU1RtKSAlaW4lIG5vblZlcm9ucG9wcykpLC0od2hpY2goY29sbmFtZXMoZ3NsRlNUbSkgJWluJSBub25WZXJvbnBvcHMpKV0KICB9CiAgaWYobGVuZ3RoKHJvd25hbWVzKGdzbEZTVG0pKTw1KXthbGwuZ3NsLnJkYVtbZ3NsXV08LSJGZXdlciB0aGFuIDUgc2FtcGxlZCBwb3B1bGF0aW9ucyI7Y2F0KCJGZXdlciB0aGFuIDUgc2FtcGxlZCBwb3B1bGF0aW9ucyIpO25leHR9CiAgCiAgI2FuZCBmaWx0ZXIgc3AgYmFzZWQgb24gdGhlIGxvY2FsaXRpZXMgdGhhdCBoYXZlIEZzdCB2YWx1ZXMKICBzcDwtc3Bbc3Akc2FtcGxlICVpbiUgcm93bmFtZXMoZ3NsRlNUbSksXQogIAogICNhbmQgdmljZSB2ZXJzYQogIAogIGdzbEZTVG08LSBnc2xGU1RtW3doaWNoKHJvd25hbWVzKGdzbEZTVG0pICVpbiUgdW5pcXVlKHNwJHNhbXBsZSkpLHdoaWNoKHJvd25hbWVzKGdzbEZTVG0pICVpbiUgdW5pcXVlKHNwJHNhbXBsZSkpXQogIAoKICBpZihsZW5ndGgocm93bmFtZXMoZ3NsRlNUbSkpPDUpe2FsbC5nc2wucmRhW1tnc2xdXTwtIkZld2VyIHRoYW4gNSBzYW1wbGVkIHBvcHVsYXRpb25zIjtjYXQoIkZld2VyIHRoYW4gNSBzYW1wbGVkIHBvcHVsYXRpb25zIik7bmV4dH0KICAKICAjY3JlYXRlIGEgbG9jYXRpb25zIGRhdGEgZnJhbWUgdGhhdCBoYXMgYWxsIHRoZSBsb2NhbGl0aWVzIHBsdXMgbGF0cyBhbmQgbG9uZ3MgYW5kIHRoZWlyIFZlcm9uIHJlZ2lvbi4KICBsb2NzPC1hcy5kYXRhLmZyYW1lKHVuaXF1ZShzcCRzYW1wbGUpKQogIG5hbWVzKGxvY3MpPC0ic2FtcGxlIgogICNsb2NzJExvbmc8LXNwJGRlY2ltYWxMb25naXR1ZGVbd2hpY2gobG9jcyAlaW4lIHNwJHNhbXBsZSldCiAgI2Nhbid0IGRvIGEgdW5pcXVlIG9uIHNhbXBsZSwgbGF0cyBhbmQgbG9uZ3MgYmVjYXVzZSBzb21lIHNhbXBsZXMgaGF2ZSBub24tdW5pcXVlIGxhdHMgYW5kIGxvbmdzISBTbyBJIGRvIGEgam9pbiBhbmQgdGFrZSB0aGUgZmlyc3QgbWF0Y2guCiAgbG9jczwtam9pbihsb2NzLHNwW2MoInNhbXBsZSIsImRlY2ltYWxMb25naXR1ZGUiLCJkZWNpbWFsTGF0aXR1ZGUiCiAgICAgICAgICAgICAgICAgICAgICAgLCJWZXJvbkRpdmlzIildLCBieT0ic2FtcGxlIiwgbWF0Y2g9ImZpcnN0IikKICBpZiAobGVuZ3RoKHVuaXF1ZShsb2NzJFZlcm9uRGl2aXMpKSA8IDIpIHsiT25seSBvbmUgcmVnaW9uISI7IGNhdCgiT25seSBvbmUgcmVnaW9uISIpOyBuZXh0fQogIAogICNzb3J0IGdzbEZTVG0KICBnc2xGU1RtPC1nc2xGU1RtW29yZGVyKHJvd25hbWVzKGdzbEZTVG0pKSxvcmRlcihjb2xuYW1lcyhnc2xGU1RtKSldCgogIAogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKICAjIDQuIENhbGN1bGF0ZSBHcmVhdCBDaXJjbGUgRGlzdGFuY2UKICBnY2Rpc3Rfa20gPC0gcG9pbnREaXN0YW5jZShsb2NzWywyOjNdLGxvbmxhdD1UKS8xMDAwCiAgIyBhbmQgc3ltbWV0cmljaXNlIGl0CiAgZ2NkaXN0X2ttW3VwcGVyLnRyaShnY2Rpc3Rfa20pXTwtMAogIGdjZGlzdF9rbTwtZ2NkaXN0X2ttICsgdChnY2Rpc3Rfa20pCiAgIAogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIENhbGN1bGF0ZSBPdmVyd2F0ZXIgRGlzdGFuY2VzIwogICNTYXZlIGZvciBsYXRlciMjCgogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwogICM1LiBDcmVhdGUgYSBtYXRyaXggb2YgcmVnaW9uYWwgaWRlbnRpdGllcwogIAogIHJlZ2lvbnM8LXdpdGgobG9jcywgZGF0YS5mcmFtZShtb2RlbC5tYXRyaXgoflZlcm9uRGl2aXMrMCkpKSAgICNvbmUgb2YgdGhlIHByZWRpY3RvcnMgaXMgc3VwZXJmbHVvdXMgYnV0IHdpbGwgZ2V0IGtub2NrZWQgb3V0IGR1cmluZyBSREEKICByb3cubmFtZXMocmVnaW9ucyk8LXJvdy5uYW1lcyhsb2NzKQogIAoKICAgICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKICAgICMgNy4gQ2FsY3VsYXRlIHRoZSBwcmluY2lwYWwgY29vcmRpbmF0ZXMKICAgIAogICAgRlNULnBjb2E8LWNtZHNjYWxlKGdzbEZTVG0sIGs9ZGltKGFzLm1hdHJpeChnc2xGU1RtKSlbMV0gLSAxLCBlaWc9VFJVRSwgYWRkPUZBTFNFKSAjaWdub3JlIHdhcm5pbmdzIC0gT0sgdG8gaGF2ZSBuZWdhdGl2ZXMgYWNjb3JkaW5nIHRvIEFuZGVyc29uCiAgICBGU1Quc2NvcmVzPC1GU1QucGNvYSRwb2ludHMKICAgIAogICAgZ2NkaXN0LnBjb2E8LWNtZHNjYWxlKGdjZGlzdF9rbSwgaz0yLCBlaWc9VFJVRSwgYWRkPUZBTFNFKQogICAgZ2NkaXN0LnNjb3JlczwtZ2NkaXN0LnBjb2EkcG9pbnRzCiAgICBnY2Rpc3Quc2NvcmVzPC1kYXRhLmZyYW1lKCJwY3giPWdjZGlzdC5wY29hJHBvaW50c1ssMV0sInBjeSI9Z2NkaXN0LnBjb2EkcG9pbnRzWywyXSkKICAgIGxvY3MyPC1jYmluZChyZWdpb25zLGdjZGlzdC5zY29yZXMpCiAgICAKICAgICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwogICAgIyA4LiBDYWxjdWxhdGUgdGhlIFJEQSBhbmQgZXh0cmFjdCBzdGF0aXN0aWNzCiAgICBSREEucmVzPC1yZGEoRlNULnNjb3Jlc34uLCBkYXRhPWxvY3MyLCBzY2FsZT1UUlVFICkKICAgIAogICAgI0V4dHJhY3QgU3RhdGlzdGljcwogICAgY29uc3RyYWluZWQuaW5lcnRpYTwtc3VtbWFyeShSREEucmVzKSRjb25zdHIuY2hpCiAgICB0b3RhbC5pbmVydGlhPC1zdW1tYXJ5KFJEQS5yZXMpJHRvdC5jaGkKICAgIHByb3BvcnRpb24uY29uc3RyYWluZWQuaW5lcnRpYTwtY29uc3RyYWluZWQuaW5lcnRpYS90b3RhbC5pbmVydGlhCiAgICAKICAgIGFkai5SMi50b3RhbC5tb2RlbDwtUnNxdWFyZUFkaihSREEucmVzKSRhZGouci5zcXVhcmVkCiAgICBpZihpcy5uYShhZGouUjIudG90YWwubW9kZWwpKXtjYXQoIlByZWRpY3RvcnMgPj0gT2JzZXJ2YXRpb25zISBObyBzb2x1dGlvbiIpO2FsbC5nc2wucmRhW1tnc2xdXTwtIlByZWRpY3RvcnMgPj0gT2JzZXJ2YXRpb25zISBObyBzb2x1dGlvbiI7bmV4dH0KICAgIAogICAgbW9kZWwuc2lnPC1hbm92YS5jY2EoUkRBLnJlcywgc3RlcD0xMDAwKQogICAgbW9kZWxGPC1tb2RlbC5zaWckRlsxXQogICAgbW9kZWxQdmFsdWU8LW1vZGVsLnNpZyRgUHIoPkYpYFsxXQogICAgCiAgICB0ZXJtcy5zaWc8LWFub3ZhKFJEQS5yZXMsIGJ5PSJ0ZXJtIiwgc3RlcD0xMDAwKQogICAgcGN4X1ZhcjwtdGVybXMuc2lnJFZhcmlhbmNlWzFdCiAgICBwY3hfcDwtdGVybXMuc2lnJGBQcig+RilgWzFdCiAgICBwY3lfVmFyPC10ZXJtcy5zaWckVmFyaWFuY2VbMl0KICAgIHBjeV9wPC10ZXJtcy5zaWckYFByKD5GKWBbMl0KICAgIAogICAgI2V4dHJhY3QgYWxsIHZhcmlhbmNlIHZhbHVlcyBpbnRvIGEgZGF0YWZyYW1lCiAgICB0ZXJtLnZhcjwtYXMuZGF0YS5mcmFtZSh0KHRlcm1zLnNpZ1ssMl0pKQogICAgbmFtZXModGVybS52YXIpPC1yb3duYW1lcyh0ZXJtcy5zaWcpCiAgIAogICAgI2V4dHJhY3QgYWxsIHAtdmFsdWVzIGludG8gYSBkYXRhZnJhbWUKICAgIHRlcm0ucHZhbDwtYXMuZGF0YS5mcmFtZSh0KHRlcm1zLnNpZ1ssNF0pKQogICAgbmFtZXModGVybS5wdmFsKTwtcm93bmFtZXModGVybXMuc2lnKQogICAgCiAgICAgCiAgICAjIHNjYWxlIHRoZSB2YXJpYW5jZQogICAgdGVybS52YXI8LXRlcm0udmFyL3N1bSh0ZXJtLnZhcikKICAgIAogICAgIyBzZXQgdmFyaWFuY2UgdG8gemVybyBpZiBpdCBpcyBub3Qgc2lnbmlmaWNhbnQKICAgIHRlcm0udmFyWzEsd2hpY2godGVybS5wdmFsWzEsXSA+IDAuMDUgfCBpcy5uYSh0ZXJtLnB2YWxbMSxdKSldPC0wCiAgICAKICAgICNzZXQgYWxsIHZhbHVlcyB0byB6ZXJvIGlmIHRoZSBtb2RlbCBpdHNlbGYgaXMgbm90IHNpZ25pZmljYW50CiAgICBpZihtb2RlbFB2YWx1ZSA+IDAuMDUpewogICAgdGVybS52YXJbMSx3aGljaChuYW1lcyh0ZXJtLnZhcikhPSJnc2wiKV08LTAKICAgIH0KICAgICMgYWRkIG9uIHRoZSBzcGVjaWVzIG5hbWUKICAgIHRlcm0ucHZhbCRnc2w8LWdzbAogICAgdGVybS52YXIkZ3NsPC1nc2wKICAgIAogICAgI21lcmdlIHRoZW0gb24gdG8gZWFjaCBkYXRhZnJhbWUKICAgIHRlcm0udmFyczwtbWVyZ2UodGVybS52YXJzLHRlcm0udmFyLGFsbD1UKQogICAgdGVybS5wdmFsczwtbWVyZ2UodGVybS5wdmFscyx0ZXJtLnB2YWwsYWxsPVQpCiAgICAKICAgIAogICAgCiAgICAjYmFycmllcl9WYXI8LXRlcm1zLnNpZyRWYXJpYW5jZVszXSAgICNvbWl0dGluZyBmb3Igbm93IGFzIHRoZSBudW1iZXIgb2YgYmFycmllcnMgd2lsbCBkaWZmZXIKICAgICNiYXJyaWVyX3A8LXRlcm1zLnNpZyRgUHIoPkYpYFszXQogICAgCiAgICAjbWFyZy5zaWc8LWFub3ZhKFJEQS5yZXMsIGJ5PSJtYXJnaW4iLCBzdGVwPTEwMDApCiAgICAjYmFycmllcl9tYXJnVmFyPC1tYXJnLnNpZyRWYXJpYW5jZVszXQogICAgI2JhcnJpZXJfbWFyZ3A8LW1hcmcuc2lnJGBQcig+RilgWzNdCiAgICAKICAgICNNb2RlbCBzZWxlY3Rpb24KICAgIG51bGxtb2RlbDwtcmRhKEZTVC5zY29yZXN+MSwgZGF0YT1sb2NzMiwgc2NhbGU9VFJVRSApCiAgICBmb3J3YXJkLm1vZGVsPC1vcmRpUjJzdGVwKG51bGxtb2RlbCwgc2NvcGU9Zm9ybXVsYShSREEucmVzKSwgZGlyZWN0b249ImZvcndhcmQiLCBwc3RlcHM9MTAwMCkgICNvcmRpUjJzdGVwIGltcGxlbWVudHMgQmxhbmNoZXRzIHN0b3BwaW5nIGNyaXRlcmlvbgogICAgYmVzdG1vZGVsPC1hcy5jaGFyYWN0ZXIoZm9yd2FyZC5tb2RlbCRjYWxsWzJdKQogICAgaWYgKGlzLm51bGwoc3VtbWFyeShmb3J3YXJkLm1vZGVsKSRjb25zdHIuY2hpKSkgewogICAgICBjb25zdHJhaW5lZC5pbmVydGlhLmJlc3Q8LU5BCiAgICAgIHRvdGFsLmluZXJ0aWEuYmVzdDwtc3VtbWFyeShmb3J3YXJkLm1vZGVsKSR0b3QuY2hpCiAgICAgIHByb3BvcnRpb24uY29uc3RyYWluZWQuaW5lcnRpYS5iZXN0PC1OQQogICAgICBhZGouUjIuYmVzdC5tb2RlbDwtTkEKICAgIH0gZWxzZSB7CiAgICAgIGNvbnN0cmFpbmVkLmluZXJ0aWEuYmVzdDwtc3VtbWFyeShmb3J3YXJkLm1vZGVsKSRjb25zdHIuY2hpCiAgICAgIHRvdGFsLmluZXJ0aWEuYmVzdDwtc3VtbWFyeShmb3J3YXJkLm1vZGVsKSR0b3QuY2hpCiAgICAgIHByb3BvcnRpb24uY29uc3RyYWluZWQuaW5lcnRpYS5iZXN0PC1jb25zdHJhaW5lZC5pbmVydGlhLmJlc3QvdG90YWwuaW5lcnRpYS5iZXN0CiAgICAgIGFkai5SMi5iZXN0Lm1vZGVsPC1Sc3F1YXJlQWRqKGZvcndhcmQubW9kZWwpJGFkai5yLnNxdWFyZWQKICAgIH0KICAgICAKICAKICAgICNzYXZlIHN0YXRzCiAgICAKICAgIHN0YXRzX21vZGVsPC1jKGdzbCxjb25zdHJhaW5lZC5pbmVydGlhLHRvdGFsLmluZXJ0aWEscHJvcG9ydGlvbi5jb25zdHJhaW5lZC5pbmVydGlhLGFkai5SMi50b3RhbC5tb2RlbCxtb2RlbEYsbW9kZWxQdmFsdWUscGN4X1ZhcixwY3hfcCxwY3lfVmFyLHBjeV9wLCBiZXN0bW9kZWwsIGNvbnN0cmFpbmVkLmluZXJ0aWEuYmVzdCwgdG90YWwuaW5lcnRpYS5iZXN0LCBwcm9wb3J0aW9uLmNvbnN0cmFpbmVkLmluZXJ0aWEuYmVzdCwgYWRqLlIyLmJlc3QubW9kZWwpCiAgICAKICAgIHN0YXRzW25yb3coc3RhdHMpKzEsXTwtc3RhdHNfbW9kZWwKICAgIGFsbC5nc2wucmRhW1tnc2xdXTwtUkRBLnJlcwogICAgCiAgICAKIAogIH0KCndyaXRlLmNzdih0ZXJtLnZhcnMsZmlsZT0iLi9vdXRwdXQvZGJSREFfdGVybV92YXJzX1dDVEhFVEEuY3N2IikKd3JpdGUuY3N2KHRlcm0ucHZhbHMsZmlsZT0iLi9vdXRwdXQvZGJSREFfdGVybV9wdmFsc19XQ1RIRVRBLmNzdiIpCgogc2F2ZShhbGwuZ3NsLnJkYSxmaWxlPSIuL291dHB1dC9tdWx0aWJhcnJpZXJfZGJSREFfV0NUSEVUQS5SZGF0YSIpCiAgCndyaXRlLmNzdihzdGF0cywgIi4vb3V0cHV0L211bHRpYmFycmllcl9kYlJEQV9KT1NURC5jc3YiKQogIApgYGAKCiMjIE1ha2UgYSBoZWF0bWFwIG9mIHRoZSB2YXJpYW5jZSB2YWx1ZXMKCgpgYGB7cn0KCgojbWVsdCBmb3IgZ2dwbG90Mgp2YXJpYW5jZV9tZWx0ZWQ8LW1lbHQodGVybS52YXJzLGlkLnZhcnMgPSAiZ3NsIikKY29sbmFtZXModmFyaWFuY2VfbWVsdGVkKTwtYygiU3BlY2llcyIsIlZhcmlhYmxlIiwiUHJvcG9ydGlvbl9vZl9WYXJpYW5jZSIpCnZhcmlhbmNlX21lbHRlZCRTcGVjaWVzPC1hcy5mYWN0b3IodmFyaWFuY2VfbWVsdGVkJFNwZWNpZXMpCgojYmFzZXBsb3QKZGJyZGE8LWdncGxvdCh2YXJpYW5jZV9tZWx0ZWQsYWVzKHk9U3BlY2llcyx4PVZhcmlhYmxlLGZpbGw9UHJvcG9ydGlvbl9vZl9WYXJpYW5jZSkpCgojYWRkIGdlb21fdGlsZSwgdHVybiB0aGUgeC1heGlzIGVsZW1lbnRzIGJ5IDkwIGRlZ3JlZXMsIHJldmVyc2UgdGhlIG5hbWVzIG9uIHRoZSB5LWF4aXMsIGFuZCB1c2UgYSBkaXZlcmdpbmcgY29sb3Igc2NoZW1lIHRvIGhpZ2hsaWdodCBoeXBvdGhlc2VzIHdpdGggPjUwJSByZWwgcHJvYi4KZGJyZGE8LWRicmRhK2dlb21fdGlsZSgpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpKwogIHlsaW0ocmV2KGxldmVscyh2YXJpYW5jZV9tZWx0ZWQkU3BlY2llcykpKSsKICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnM9Yygid2hpdGUiLCJwaW5rIiwicmVkIiksdmFsdWVzID0gYygwLDAuMDAwMDAxLDEpLAogICAgICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gImdyZXk1MCIsIGd1aWRlID0gImNvbG91cmJhciIpCgpkYnJkYQpgYGAK